home *** CD-ROM | disk | FTP | other *** search
/ Ham Radio 2000 / Ham Radio 2000.iso / ham2000 / antenna / azproj10 / az_proj.ps < prev    next >
Text File  |  1995-07-19  |  143KB  |  5,209 lines

  1. %%--------------------------------------
  2. %% AZ_PROJ.PS v1.0
  3. %%Creator: Joseph Mack NA3T (ex VK2ZJM/VK2BME) and Michael Katzmann NV3Z/VK2BEA/G4NYV
  4. %%Title: az_proj.ps Ver 1.0
  5. %%CreationDate: Thu 19 Jul 95
  6. %
  7. % Last modification 19 Jul 95, JM
  8. % Is Joe's file az_projz.ps
  9. %
  10. %--------------------------------------
  11. % A 'beta' version was released at the Central States and
  12. % the Eastern States VHF Conferences, 1994 for evaluation purposes.
  13. % This is the first general release version.
  14. % You may freely redistribute this version.
  15. % Note: the data file format is incompatible with that of the beta release -
  16. %    don't mix versions.
  17. %--------------------------------------
  18.  
  19. % AZ_PROJ.PS (C) 1994, 1995 Joseph Mack NA3T and Michael Katzmann NV3Z/VK2BEA/G4NYV
  20. %
  21. % AZ_PROJ.PS is free software; you can redistribute it and/or modify
  22. % it under the terms of the GNU General Public License as published by
  23. % the Free Software Foundation; either version 2, or (at your option)
  24. % any later version.
  25. %
  26. % This program is distributed in the hope that it will be useful,
  27. % but WITHOUT ANY WARRANTY; without even the implied warranty of
  28. % MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.    See the
  29. % GNU General Public License for more details.
  30. %
  31. % You should have received a copy of the GNU General Public License
  32. % along with AZ_PROJ.PS; see the file COPYING.    If not, write to
  33. % the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
  34. %
  35.  
  36. % AZ_PROJ.PS - A program to print Azimuthal equidistant map projections
  37. % on a Postscript device or via a Postscript interpreter (e.g. ghostscript)
  38.  
  39. % If you find any bugs or have ideas for enhancements, please code them
  40. % and send them to us. We will post updates occasionally, and include
  41. % your code with acknowledgment.
  42.  
  43. % We are contactable at -
  44. % Joseph Mack NA3T, (FM19gk)
  45. % 528 Grant Pl
  46. % Frederick, MD. 21702-4142, USA (will be moving from here Aug 95)
  47. %
  48. % call me in this order please
  49. % e-mail: mack@ncifcrf.gov (will be valid after move)
  50. % ph: USA (301)-662-3486 (home - evenings only please -
  51. % - message machine usually, OK till 10pm = 0300 UTC)
  52.  
  53.  
  54. % Michael Katzmann NV3Z / VK2BEA / G4NYV, (FM18rx)
  55. % 501 Defense Highway
  56. % Annapolis, MD. 21410-6923
  57. %
  58. % e-mail: michael%vk2bea@secondsource.COM
  59. % packet: nv3z@w3zh.md
  60. % ph: USA (410) 672-3900 (work EST, UTC -5hrs)
  61.  
  62. %--------------------------------------
  63.  
  64. % PostScript is a trademark of Adobe Systems, Incorporated.
  65. % Ghostscript is Copyright (C) 1990, 1992, 1993 Aladdin Enterprises.
  66. % DesqviewX is a trademark of Quarterdeck.
  67.  
  68. % Note: the az_proj files are PostScript. They run on any platform
  69. % that understands PostScript, eg a PostScript printer or a PC, Mac,
  70. % or Unix box running a PostScript interpreter (eg Ghostscript).
  71. %
  72. % The az_proj files were verified on these platforms:
  73. %    - NEC LC890 Silentwriter with Adobe Postscript (Level 1)
  74. %    - HP1200C/PS Color deskjet with Adobe Postscript (Level 2)
  75. %    - Ghostscript 2.6.2 executing under MSDOS 6.2, MS Windows 3.1
  76. %    or DesqviewX v2.0/ghostscript_dvx v2.6.1, v3.1.2, v3.3.3
  77. % operating under MSDOS5.0, both on
  78. %    Intel 486 hardware with hardcopy output to HP Deskjet550C.
  79. %    - Ghostscript 2.6.2 executing under HP/UX 9.0 X11R5
  80. %    on HP9000/380 with hardcopy output to HP Deskjet 500.
  81. % On a Mac Quadra 950 and Phaser II color printer.
  82.  
  83. % Ghostscript is freely available (with the GNU License) from
  84. % ftp.cs.wisc.edu:/pub/ghost, and from the GNU servers everywhere.
  85.  
  86. % The Jul '94 price for Ghostscript on PC diskettes is US$48
  87. % (includes shipping, handling, etc) payable by check or money
  88. % order to Aladdin Enterprises and mailed to:
  89. %
  90. %    Aladdin Enterprises
  91. %    203 Santa Margarita Ave.
  92. %    Menlo Park, CA, 94025, USA
  93. %
  94. % The author of ghostscript, L. Peter Deutsch is contactable at
  95. %    Aladdin Enterprises
  96. %    P.O.Box 60264,
  97. %    Palo Alto, CA 94306, USA
  98. % or at
  99. %    ghost@aladdin.com
  100. %    decwrl!aladdin!ghost
  101. %    voice USA (415)-322-0103
  102. %    fax   USA (415)-322-1734
  103. %
  104. %--------------------------------------
  105. %
  106. % n.b. Execution times vary greatly with platforms. Many Postscript
  107. %    printers are not be equipped with floating point hardware and
  108. %    will consequently be slow. (also consider the time taken to
  109. %    send in excess of 4MB of data files to the printer!)
  110. %
  111. % some benchmarks (full world database & annotations):
  112. %    Ghostscript on HP9000/380 X11R5 -    8 mins
  113. %    Ghostscript on i486 (66MHz) VGA -    7 mins
  114. %    HP1200C/PS printer        -    2.1 hrs
  115. %    NEC LC890 PS printer        -    6.7 hrs
  116. %
  117.  
  118. %--------------------------------------
  119. % Modus operandi for
  120. % a) native Postscript printers
  121. % b) Postscript Interpreters running on host computers,
  122. %    which output native print codes for the target printer.
  123. %
  124. %Input files:
  125. % If you have a native Postscript Printer
  126. %    A real postscript printer can only listen to the line down which
  127. %    the postscript file itself is sent. Postscript printers don't,
  128. %    in general, know about files (the exception is Display PS)
  129. %    When a PS printer gets an EOF it knows it has come to
  130. %    the end of the job. If you want to print a map of the whole
  131. %    world on a real postscript printer you must make ONE file by
  132. %    concatonating "az_proj.ps" and, all of the data files (eg ".wdb",
  133. %    dxcc.dat, beacon.dat). i.e. the data must appear as an uninterrupted
  134. %    stream.
  135. %
  136. %    Note that the data will be drawn on the page in the order received
  137. %    by the printer. e.g. One beacon is on the edge of the Great Lakes.
  138. %    If beacons are drawn first, this beacon will be overwritten by the
  139. %    lake (if drawn in "fill" mode). So send beacons after lakes and countries.
  140. %
  141. %    for DOS:
  142. %    The command line would then be something like
  143. %        C:\> PRINT AZ_COMB.PS
  144. %    where AZ_COMB.PS is the combined data file. The combined data
  145. %    file can be produced by a file similar to makworld.bat
  146. %    (supplied with AZ_PROJ) that has the one line instruction -
  147. %
  148. %    C:\>copy az_ini.ps+az_proj.ps+africa.wdb+antarct.wdb+eurasia.wdb+n_amer.wdb+
  149. %        oceania.wdb+s_amer.wdb+dxcc.dat+beacon.dat+ctrld.ps az_comb.ps
  150. %        (all on one line)
  151. %
  152. %    for UNIX:
  153. %        $ cat az_ini.ps az_proj.ps *.wdb dxcc.dat |lp
  154. %
  155. %    n.b. when using an Adobe Postscript equipped printer, You MUST
  156. %    have an EOF character (ctrl D, ^D) at the end of the data stream .
  157. %    Most printer spoolers designed for a PS printer will do this
  158. %    but if they don't, you must explicitly supply it. The file
  159. %    'ctrld.ps' (supplied with azproj), can be used for this task,
  160. %    as in the DOS example above.
  161. %
  162. %Ghostscript processed files
  163. %    Ghostscript is a program, run on a computer, which interprets
  164. %    the Postscript language and outputs print codes suitable for
  165. %    specific printers and screens.
  166. %    Ghostscript knows about files. You can send multiple .WDB
  167. %    files to ghostscript as command line parameters.
  168. %
  169. %    MS-DOS:
  170. %    The command line for screen viewing (see AZVIEW.BAT), would then be
  171. %    C:\> gs386 -q az_ini.ps -- az_proj.ps n_amer.wdb dxcc.dat
  172. %
  173. %    To create to a print file `n_amer.cdj' (see AZPRINT.BAT),
  174. %    which can then be sent to a HP deskjet 550 (all on one line)
  175. %    gs386 -q -sDEVICE=cdj550 -sOutputFile=n_amer.cdj az_ini.ps --
  176. %        az_proj.ps n_amer.wdb dxcc.dat
  177. %
  178. %    Note that the MSDOS command PRINT will only work for ascii files.
  179. %    The file n_amer.cdj is binary must be printed using something like
  180. %    C:>copy/b n_amer.cdj lpt1:
  181. %    (Better to use a good DOS spooler like the shareware dmp)
  182. %
  183. %    The following command sends directly to PRN
  184. %    gs386 -q -sDEVICE=cdj550 az_ini.ps -- az_proj.ps n_amer.wdb dxcc.dat
  185. %
  186. %    UNIX: to send directly to the printer
  187. %    (without creating an intermediate file):
  188. %    gs -q -sDEVICE=cdj550 '-sOutputFile=|lp -or -onb' \
  189. %        -r300 -dNOPAUSE az_ini.ps -- az_proj.ps n_amer.wdb dxcc.dat
  190.  
  191. %--------------------------------------
  192. % Credits, Thanks and more explanations
  193.  
  194. % WDB files
  195. %    The data files come from the Micro World Data Bank II (MWDB-II).
  196. %    Mike Owen W9IP pointed us to this resource.
  197. %    The binary data was converted by one of the utility programs
  198. %    in the set, to the ASCII form used here (the .wdb files).
  199. %    Each line in the .wdb files has the form
  200. % integer    lat    lon    comment
  201. %    representing a point on the earth's surface. If the integer
  202. %    is a 4 digit number then this point is the start of
  203. %    a new path (ie line) to be drawn on the earth's surface.
  204. %    The four digit integer is a label showing -
  205.  
  206.     % 1xxx, coast lines
  207.     % 2xxx, country borders
  208.     % 3xxx, Canadian Provinces
  209.     % 4xxx, US state borders
  210.     % 5xxx, islands
  211.     % 6xxx, lakes
  212.     % 7xxx, rivers
  213.     % 8xxx, Australian States
  214.  
  215. %    A new 4 digit integer terminates an old path and starts a new one.
  216. %
  217. %    If the integer is a single digit, it has the value 1..5 and
  218. %    represents the resolution level (1 - highest detail, 5 - least detail).
  219. %    If you want faster (and less detailed) plotting, then only the lower
  220. %    resolution data need be used. We haven't had time to implement this
  221. %    feature, consequently all data is plotted everytime. Anything in
  222. %    the data line after the first    three numbers is ignored by this
  223. %    program. Comments or names of the features (eg `% Lake Baikal')
  224. %    can be put at the end of the data line.
  225. %
  226. %    The original .wdb files, as extracted from the database, are sorted
  227. %    into separate files for countries, coasts, rivers, lakes, islands etc.
  228. %    If you are a VHF operator, you are more likely to be using data for
  229. %    one continent, so I have manually sorted the data into continent files
  230. %    (n_amer.wdb, oceania.wdb etc), each file having the coastlines,
  231. %    countries, islands, states, rivers, lakes for that continent.
  232. %    If you are plotting the top of Siberia using the file eurasia.wdb
  233. %    and want N.A. to appear in the same plot, then you will have to
  234. %    send the file n_amer.wdb to the printer as well.
  235.  
  236. %    Originally the lower numbered lines (eg 2xxx) were first in
  237. %    the .wdb files. However if a river (6xxx) or lake (7xxx) is also
  238. %    a political border, then the black political line is later
  239. %    covered over with a green (river) or blue (lake) line.
  240. %    In case you're looking for a black political borders, and don't
  241. %    want them covered by a colored river, I've moved the rivers and lakes
  242. %    to an earlier part of the WDB files. Thus the Rio Grande is a (green)
  243. %    river in New Mexico, but as it travels south it becomes a (black)
  244. %    border between Texas and Mexico. It looks a little weird to see a
  245. %    colored line change back and forth to a black line. It's my best
  246. %    solution so far. If you've any better ideas, let me know. If you're
  247. %    watching the map being drawn on a screen, you will see the rivers
  248. %    and lakes drawn before country and state borders.
  249. %    A partial solution is to make the state borders dashed
  250. %    (see /state_borders_dashed).
  251. %
  252. %    The lines which describe the lakes are have been hand modified
  253. %    so that they are now closed paths. So it is now possible to fill
  254. %    a lake with one color or just to stroke the outline (see the
  255. %    variable /lake_fill). (Anyone have the co-ords for Lake
  256. %    Champlain, Lake Fromme... ?)
  257. %
  258. %    Here are some of the notations that come with the WDB -
  259. %
  260. %    "The full WDB-II is a digital map data base produced by the
  261. %    Central Intelligence Agency (CIA) and distributed by the National
  262. %    Technical Information Service (NTIS), U.S. Department of Commerce,
  263. %    5285 Port Royal Road, Springfield, VA, 22161.
  264. %    ...
  265. %
  266. %    This documentation and the associated files are placed in the
  267. %    public domain and may incorporated into other products without fee so
  268. %    long as appropriate credits are included. An appropriate credit line
  269. %    would be - "This product contains/uses data and/or code placed in the
  270. %    public domain by Fred Pospeschil and Antonio Riveria. Original
  271. %    coordinate data was created by the Central Intelligence Agency."
  272. %
  273. %    ALL USERS OF THESE MATERIALS ARE TOTALLY RESPONSIBLE FOR THEIR
  274. %    USE AS THESE MATERIALS ARE PROVIDED WITHOUT EITHER EXPRESS OR IMPLIED
  275. %    WARRANTIES OF ANY KIND."
  276. %
  277. %    - end of excerpt from the WDB docs.
  278.  
  279. % Routine GC
  280. %    The routine gc was adapted from gc.c, Ver 1.01
  281. %    S. R. Sampson, N5OWK, Public Domain (p) November 1989,
  282. %    Ref: Air Force Manual 51-40, "Air Navigation", 1 February 1987
  283.  
  284. % Call/zone file (dxcc.dat):
  285. %    The ARRL list of dxcc call zones in machine readable form
  286. %    is maintained by Bill Brelsford, K2DI.
  287. %    The file is available by ftp to
  288. %    ftp.cs.buffalo.edu:/pub/ham-radio/dxcc-k2di
  289. %    or by sending e-mail containing the line
  290. %        send dxcc-k2di
  291. %    to info@arrl.org
  292. %    The listing we are using was updated in 1 Jul 94. Note that
  293. %    while the .WDB files have been broken down into continents,
  294. %    the dxcc.dat file is for the whole world. If you combine
  295. %    only one continent file and the dxcc file, you will get
  296. %    some dxcc names printed in the "sea".
  297.  
  298. %Annotation file (annotation):
  299. %    To add a notation to the map, supply data in the form
  300. %        annotate:Notation:Lat:Lon
  301. %    eg.    annotate:NV3Z:38.98847N:76.58033W
  302.  
  303. %Beacon File
  304. %    To add a beacon to the map, supply data in the form
  305. %    beacon:frequency Callsign Grid_locator Power Direction
  306. %    eg.    beacon:144.170 KH6HME BK29go 60 90 1
  307. %    (if no beam direction is given or if it is 360, then it is omni)
  308. %    (the trailing '1' is a flag to print the info below the symbol,
  309. %    rather than on top, which is the default. The flag is optional)
  310. %    The beacon file, bea_w3ep.dat, is maintained by Emil Pocock, W3EP.
  311. %    Emil writes the `World above 50MHz' column in QST. Please send
  312. %    beacon updates to Emil and we will get them from him.
  313. %    Sorry, this file we have only has US beacons.
  314. %    The 6m beacon file, bea_6m.dat, is from
  315. %    M. Harrison, <poa01@cc.keele.ac.uk>.
  316. %
  317. %    CAVEAT: Some of the beacons are directional. Unless the
  318. %    beacon is relatively close (say 500-100km depending on
  319. %    the accuracy you're interested in), then the path of the
  320. %    radio wave (which is following a great circle) will be
  321. %    curved on the map (like the lines of constant longitude).
  322. %    Only the great circle lines to and from the QTH are straight
  323. %    on this projection. So if the beacon is pointing at you on
  324. %    the azimuthal projection map it will be pointing at you in
  325. %    physical reality too. However if the map says it is pointing
  326. %    somewhere else, you may not even be able to guess the path
  327. % of the radio wave on the map surface. For that you should do
  328. %    a projection from the beacon's site.
  329. %
  330. %Repeater files:
  331. %    A repeater file has the same format as a beacon file.
  332. %    The lines start with r: and R: (rather than b: and B:),
  333. %    so that repeaters can be differentiated from beacons.
  334. %    Unfortunately the ARRL is not allowed to release the contents
  335. %    of their repeater directory, because of a non-release clause
  336. %    required by most repeater coordinators before parting with
  337. %    their lists. Apparently repeater information is regarded as
  338. %    proprietary by repeater coordinators. If you are able to pry
  339. %    your local repeater coordinator's fingers off his list then
  340. %    you can put repeaters on your map.
  341. %
  342.  
  343. % NMEA capabilities - suggested by Paul Wade N1BWT, and with help
  344. %    on the code specs by Mike Owen W9IP, an article by Wayne Simpson
  345. %    forwarded by Paul, and a lead to a WWW site by Jim KC7MJ
  346. % only GLL (Geog Lat/Lon)
  347. % and BWC (bearing to waypoint along Great Circle) are implemented.
  348. %
  349. % for info on NMEA, see the file simpson.doc included in this package
  350. %
  351. %--------------------------------------
  352. % Bugs & Caveats:
  353. %
  354. %Limitations
  355. %1:    Can't do maps from the poles (directions are south and north
  356. %    to everywhere respectively). You can make a map that looks just fine
  357. %    from say (89.9,180.0) though. Be careful of the longitude
  358. %    you pick as this will define the reference direction.
  359.  
  360. %2:    Reference Latitude and Longitude lines near the antipodes will
  361. %    wrap around by crossing back across the map. If your QTH is exactly
  362. %    on a plotted reference latitude, e.g. 15.00000 deg N, then try
  363. %    entering 15.001 deg N instead.
  364.  
  365. %3:    Postscript can be very slow when implimented in some printers.
  366. %    For a real postscript printer, maps take 20mins to 8hrs depending
  367. %    on what you plot. Ghostscript running under DesqviewX
  368. %    on a 33MHz 486 computer    takes *about* 1/2hr for plotting Nth America.
  369. %    Running under MS-DOS, it takes just over 2 mins. The Ghostscript
  370. %    screen viewer only takes a few minutes for small parts of the
  371. %    earth's surface. Remember that if you send it the whole map
  372. %    for Europe and are only looking at your local 100km, the
  373. %    program still has to calculate the whole of Europe and Asia.
  374. %    You might want to split off a particular part of your files
  375. %    if you're going to do a lot of plots of one area.
  376. %    If you re-sort any files like this into useful groupings
  377. %    please send us the new files, as it may save someone doing
  378. %    the same thing again.
  379.  
  380. %Problems near the poles:
  381. %    Due to what appears to be the single precision arithmetic
  382. %    of postscript, the routine "gc" cannot differentiate points close
  383. %    together near the poles. It becomes impossible to calculate the
  384. %    orientation of number labels near the pole for instance. These
  385. %    calculations, when they result in a divide by 0 error, are trapped
  386. %    and those labels are not drawn.
  387.  
  388. %Bugs:
  389. %1:    Get a numeric exception if QTH = (0,0) and DEST = (90,90)
  390. %
  391. %2:    Elapsed time doesn't work in DesqviewX 2.0, with ghostscript 2.6.1
  392. %
  393. %3:    There are lots of comments to help you understand the code.
  394. %    However this slows down operation when used    on a native
  395. %    Postscript printer particularly when fed by a serial line.
  396. %    Solution: Create a copy and strip out all the comments.
  397. %    You can remove comments with utilities like the freeware
  398. %    CLNCODE2, available on your local BBS.
  399.  
  400.  
  401. %Fiddles:
  402. %Close points:
  403. %    There are lots of problem points and discontinuities on a sphere
  404. %    Points "near" the antipodes are given a bearing of 0 deg
  405. %    Points closer than the numerical precision (= very_small_distance)
  406. %    are given a bearing of 0 deg. To be safe, I've defined
  407. %    "very_small_distance" to be just smaller than the resolution
  408. %    of the data. The resolution of the WDB, is 1min of arc = 0.016 deg
  409. %    (1 mile at the equator). The ASCII translation of the database
  410. %    is given to 3 figs i.e. 0.001 deg, although the original data
  411. %    is only accurate to 0.016 degree.
  412. %
  413. %    "very_small_distance" is the distance in degrees at which the
  414. %    routines will assume that DEST=QTH. This trap is to stop the
  415. %    bearing determining routine from blowing up when trying
  416. %    to determine the bearing to yourself from yourself, with
  417. %    limited precision calculations. In choosing this quantity,
  418. %    anything less than the smallest interval being plotted is OK.
  419. %
  420.  
  421. %Distant points:
  422. %    The bearing to points at the antipodes is not defined.
  423. %    Distances close to the antipodes are trapped and a
  424. %    bearing of 0 will be returned.
  425.  
  426.  
  427.  
  428. %--------------------------------------
  429.  
  430. /starttime usertime def
  431.     % gives a nonsense value with ghostscript running under DesqviewX
  432.     % but sensible numbers everwhere else
  433.  
  434. %--------------------------------------
  435.  
  436. %initialise and declare a few things
  437.  
  438. %strings, defined here to stop it chewing up VM
  439. /grid_string 10 string def
  440. /name    10    string    def
  441. /COMMA    (,)    def
  442. /CR    (\r)    def
  443. /LF    (\n)    def
  444. /temp_string 10 string def
  445.  
  446. %Conversions    % Distances: All distance calculations are done in degrees
  447.                             % along great circles, assuming a spherical earth.
  448.  
  449. /km2deg        { 10000 div 90 mul }    def
  450. /deg2km        { 10000 mul 90 div }    def
  451. /NM2deg {360 mul 21600 div} def        %Nautical Miles
  452. /M2deg {360 mul 25000 div} def        %Statute Miles (25000 or whatever the circumference is)
  453. /cm        { 28.35 mul }        def    % points in a centimeter
  454. /points2cm    { 28.35 div }        def
  455.  
  456.  
  457. %Routines
  458. % Only define arccos if it is not built in (as in ghostscript)
  459. systemdict /arccos known not { /arccos /Arccos cvx def } if
  460.  
  461. %other useful things
  462. /very_small_distance    0.001 def
  463. /distance_to_antipodes    180.0 very_small_distance sub def
  464. /incr_lim 1.0e-3 def
  465.  
  466.  
  467.  
  468. %--------------------------------------
  469. %Grid square nomenclature:
  470. % The 2x1 degree "squares" are described by a pair of letters,
  471. % eg. FM for Mid Atlantic USA.
  472. % In this program the 2x1 deg squares are called "letter_squares"
  473. %
  474. % The 0.2x0.1 degree squares are described by a pair of numbers,
  475. % eg. 19 for Washington, DC area.
  476. % In this program the 0.2x0.1 deg squares are called "number_squares"
  477. % The number squares are useful for VHF operators operating over
  478. % short distances. If drawing a large map (radius > 50 degrees)
  479. % then the number squares are turned off automatically.
  480. % Irrespective of the scale being plotted, all (i.e. the whole
  481. % world) of the letter grid squares are calculated (even if you
  482. % are only plotting 100 km out from your QTH). We haven't
  483. % figured an automatic way that can short circuit this process.
  484. % It doesn't take a lot of time compared to processing the .wdb files,
  485. % or compared to the printing so we haven't done anything to speed it up.
  486.  
  487.  
  488.  
  489. %--------------------------------------
  490. % linewidths of map features (in atom units (1/2000 * picture height))
  491. /feature_width
  492. [
  493.     2.0    % coast lines
  494.     1.5    % country borders
  495.     1.25    % Canadian Provinces
  496.     1.25  % US state boundaries
  497.     2.0    % islands
  498.     1.0    % lakes
  499.     1.25    % rivers
  500.     1.0    % Australian State boundaries
  501. ] def
  502.  
  503. %--------------------------------------
  504. % handy numbers to make code readable
  505.  
  506. /coast_line                    1    def
  507. /country_border            2    def
  508. /Canadian_province    3    def
  509. /US_state                        4    def
  510. /island                            5    def
  511. /lake                                6    def
  512. /river                            7    def
  513. /Australian_state        8    def
  514.  
  515. %--------------------------------------
  516.  
  517. /bearing_fontsize            { atom 20 mul } def
  518. /footer_label_height    { atom 30 mul } def
  519.  
  520. /annot_font                    /Helvetica-Oblique def
  521. /annot_font_size        { atom 30 mul } def
  522.  
  523. /mountain_font            /Helvetica def
  524. /mountain_font_size    { atom 30 mul } def
  525.  
  526. /rover_font                    /Helvetica def
  527. /rover_font_size        { atom 30 mul } def
  528.  
  529. /beacon_font_size        { atom 15 mul } def
  530. /width_mh                        { atom } def                %letter grid locator line width
  531. /fine_gl_width            { atom 2 div } def    %number grid locator line width
  532. /bearing_width            { atom } def
  533.  
  534.  
  535. %--------------------------------------
  536. % calculate sun_lat from day of year
  537. % 88 days to 22 March
  538. % sun_lat is 23.5 sin (((day_of_year -88)/365)x360)
  539. %
  540. % calculate sun_lon from UTC
  541. % sun_lon is (0.5-(minutes_of_day/1440))x360
  542.  
  543.  
  544. % no leap years
  545. /days_in_month  [0 31 28 31 30 31 30 31 31 30 31 30] def
  546. /calculate_sun_position
  547. {
  548. az_dict /month known
  549. az_dict /day   known and
  550. az_dict /hour  known and
  551. az_dict /min      known and
  552.     {
  553.         (Calculating sun position \n) print_notice
  554.         0 1 month 1 sub
  555.         {
  556.             %array index is on stack
  557.             days_in_month %array name
  558.             exch    %get in right order to retrieve array element
  559.             get
  560.             %(days in month ) print_notice pstack
  561.             day add /day exch def
  562.         }for
  563.         % day now contains day of year
  564.         day
  565.         %(day of year ) print_notice pstack
  566.         88 sub
  567.         365.25 div 360 mul
  568.         sin
  569.         23.5 mul
  570.         /sun_lat exch def
  571.         %sun_lat (sun_lat ) print_notice pstack pop
  572.  
  573.         hour 60 mul min add 1440 div 0.5 sub neg 360 mul /sun_lon exch def
  574.         %sun_lon (sun_lon ) print_notice pstack pop
  575.     }    if
  576. }def
  577.  
  578. %--------------------------------------
  579. % Error function for greyline
  580. % If this function is zero then the terminator lat (term_lat)
  581. % and lon (term_lon) are correct.
  582. % This is used in a Newton iteration to find term_lat, given term_lon
  583. % formula supplied by Chris Cosgrove at Sydney Uni.
  584.  
  585. /terminator_error
  586. {
  587.     % term_lat on stack
  588.     % term_lon global
  589.     % sun_lat, sun_lon are globals
  590.     % error is left on the stack on exit
  591.     /term_lat exch def
  592.  
  593.     sun_lat cos term_lat cos mul
  594.     sun_lon term_lon sub cos mul
  595.     sun_lat sin term_lat sin mul
  596.     add
  597.     %(terminator_error: ) print_notice pstack
  598. }def
  599.  
  600. %--------------------------------------
  601. % draw sun symbol at sun_lat, sun_lon
  602. /draw_sun_symbol
  603. {
  604.     /dot_radius    5 atom mul def
  605.     /sun_radius    20 atom mul def
  606.     /inner_end_of_ray 30 atom mul def
  607.     /ray_length 10 atom mul def
  608.     1 atom mul setlinewidth
  609.     greyline_color setrgbcolor
  610.  
  611.  
  612.     sun_lat sun_lon lat_lon2xy moveto
  613.     newpath
  614.     sun_lat sun_lon lat_lon2xy dot_radius 0 360 arc closepath fill
  615.     newpath
  616.     %sun_lat sun_lon lat_lon2xy moveto
  617.     sun_lat sun_lon lat_lon2xy sun_radius 0 360 arc stroke
  618.  
  619.     %draw rays around sun
  620.     7 /number_of_rays_around_sun exch def
  621.     0 360 number_of_rays_around_sun div 360
  622.     {
  623.         newpath
  624.         sun_lat sun_lon lat_lon2xy moveto
  625.         dup rotate
  626.         inner_end_of_ray 0 rmoveto
  627.         ray_length 0 rlineto stroke
  628.         neg rotate
  629.     } for
  630. }def
  631.  
  632.  
  633. %--------------------------------------
  634. % Greyline routine
  635. % calculates position of greyline using the global values, sun_lat, sun_long
  636. % being the point at which the sun is directly overhead.
  637. % assumes a spherical earth.
  638. %
  639. %    sun_lat, sun_lon come from az_ini.ps
  640. % or are calculated from  date/time in az_ini.ps
  641. % or date/time from NMEA codes (whenever that gets put in)
  642. %
  643. % for sun overhead at sun_lat, sun_lon the equation of the terminator
  644. % (term_lat, term_lon) is
  645. % cos(sun_lat).cos(term_lat).cos(sun_lon - term_lon)
  646. %                     + sin (sun_lat).sin(term_lat) = 0
  647. % not easy to get the answer explicitely, (due to div by zero)
  648. % so do it iteratively
  649. %
  650. % BUGS:
  651. % This is a quick and dirty routine.
  652. % 1. It has trouble with terminators going through the poles,
  653. % eg at the equinoxes (will execute but produce garbage).
  654. % i.e. when sun_lat=0.0
  655. % this is trapped below
  656. %
  657. % 2. The terminator line is calculated at even intervals of term_lon rather
  658. % than using the contour_draw algorythm (even intervals of plotting space).
  659. % So lines of most interest to some, ie where the greyline goes through
  660. % your QTH, will have jaggy lines around the antipodes,
  661. % while the lines near the QTH will be drawn in unnecessary detail. Oh well.
  662. %
  663. % 3. I can't tell which part of the map is day or night, so I
  664. % can't make one part of the map grey (ie the night side).
  665. % If you figure it out, let me know.
  666. % In the meantime, I've put a marker for the sun on the map.
  667. %
  668.  
  669. /greyline
  670. {
  671.     (Drawing Greyline \n) print_notice
  672.     %sun_lat (sun_lat ) print_notice pstack pop
  673.     %sun_lon (sun_lon ) print_notice pstack pop
  674.  
  675.     /Helvetica findfont bearing_fontsize scalefont setfont
  676.     1 atom mul setlinewidth
  677.     greyline_color setrgbcolor
  678.     0.1 /inc exch def % inc for newton iteration
  679.  
  680.     % where terminator crosses equator, ie where term_lat=0
  681.     % (ie term_lat and term_lon are known - a good place to start calculating)
  682.     %sun_lon = (sun_lon) print_notice
  683.     sun_lon 90 sub /phase_of_node exch def
  684.     phase_of_node -180 lt {phase_of_node 180 add /phase_of_node exch def} if
  685.     phase_of_node 180 gt {phase_of_node 180 sub /phase_of_node exch def} if
  686.     %phase_of_node = (phase_of_node) print_notice
  687.     % initialise lat_term, will get new value each iteration along terminator
  688.     0.0 /term_lat exch def % = 0.0 for first iteration
  689.  
  690.     %trap sun_lat == 0.0
  691.     0.0 sun_lat eq {0.5 /sun_lat exch def} if % much smaller and you get garbage
  692.  
  693.     mark    %just in case
  694.     newpath
  695.  
  696.     % go to node
  697.     term_lat phase_of_node lat_lon2xy moveto
  698.  
  699.     %draw path
  700.     %go 360 deg starting at equatorial crossing of terminator
  701.     phase_of_node 0.1 phase_of_node 360 add
  702.     {
  703.         %(term_lon ) print_notice pstack
  704.         /term_lon exch def
  705.  
  706.         {
  707.             % find slope i.e. d(terminator_error)/d(term_lon)
  708.             term_lat terminator_error dup /y1 exch def    %    y1
  709.             term_lat inc add terminator_error                        % y2
  710.             sub            % y1 - y2
  711.             inc div /error_slope exch def
  712.             %(error_slope ) print_notice error_slope pstack pop
  713.             error_slope dup mul 0.00000001 lt {exit} if % in case are at a stationary point
  714.             y1 error_slope div /shift exch def    %calculate Newton Shift
  715.             term_lat shift add /term_lat exch def        % calculate new term_lat
  716.             shift 0.0001 lt {exit} if                        % exit if done
  717.             %term_lat (term_lat ) print_notice pstack pop
  718.             %(going around again \n) print_notice
  719.         } loop % till Newton has converged
  720.  
  721.         term_lat term_lon lat_lon2xy lineto
  722.  
  723.         %term_lat term_lon pstack pop pop
  724.     } for
  725.     closepath
  726.     stroke
  727.     cleartomark %as I said, just in case
  728. }def
  729.  
  730. %--------------------------------------
  731. %Instruction to execute to display a "special" dxcc country
  732. % ie one marked with a D: in dxcc.dat
  733. /dxcc_special_country_2
  734.     {
  735.     /outlineshow {true charpath stroke} def
  736.     atom 10 div setlinewidth
  737.     /Helvetica-BoldOblique findfont
  738.     /dxcc_font_size { atom 30 mul} def    % as a fraction of screen width
  739.     dxcc_font_size scalefont setfont
  740.     dxcc_special_color_2 setrgbcolor
  741.     } def
  742.  
  743. %Instruction to execute to display a dxcc country in that you've worked
  744. /dxcc_special_country
  745.     {
  746.     /outlineshow {true charpath stroke} def
  747.     atom 10 div setlinewidth
  748.     /Helvetica-BoldOblique findfont
  749.     /dxcc_font_size { atom 25 mul} def    % as a fraction of screen width
  750.     dxcc_font_size scalefont setfont
  751.     dxcc_special_color setrgbcolor
  752.     } def
  753.  
  754.  
  755. %Instruction to execute to display a dxcc country in default mode
  756. % eg for a country that you haven't worked
  757. /dxcc_country
  758.     {
  759.     /outlineshow {show} def
  760.     /Helvetica findfont
  761.     /dxcc_font_size    { atom 25 mul } def    % as a fraction of screen width
  762.     dxcc_font_size scalefont setfont
  763.     dxcc_color setrgbcolor
  764.     } def
  765.  
  766. %--------------------------------------
  767. % special cases
  768.  
  769. /island_in_lake
  770. % these islands are in a lake.
  771. % they have to be drawn after the lake and filled with white
  772. % otherwise they will be blue (or whatever color your lake is)
  773. [
  774. 5173
  775. 5174
  776. 5175
  777. 5200
  778. ]def
  779.  
  780. /big_lakes    % big enough to have borders in black
  781.                         % I've somewhat arbitrarily decided which lakes are in this list
  782.                         % you can put them all in if you like.
  783.                         % it's an ad hoc solution otherwise small lakes become all edge
  784.                         % entries one per line, you can take a lake out of this list,
  785.                         % by putting a comment (%) symbol at the start of the line
  786. [
  787. 6058    % L. Winnipeg
  788. 6059    % Great Slave Lake
  789. 6060    % L. Athabasca
  790. 6061    % L. Ontario
  791. 6062    % L. Erie
  792. 6063    % Thunder Bay
  793. 6069    % Great Bear Lake
  794. %6070  % Teslin Lake (border BC and Yukon)
  795. 6073    % Caspian Sea and part of L. Winnipeg (don't ask me why these have the same numbers, I didn't do the numbering)
  796. 6074    % L. Ontario
  797. %6087    % L. Okeechobee
  798. 6096    % L. Nicaragua
  799. 6501    % L. Nettilling (in Baffin Is.)
  800. ]def
  801.  
  802.  
  803. %--------------------------------------
  804. %Things to do:
  805. %Cities
  806. % It would be nice to be able to display cities, in a way that only
  807. % important (whatever that means) towns are displayed on large scale
  808. % maps while on small scale maps, less important towns are brought in.
  809. % In the hopes of using populations as a measure of importance, I
  810. % unsuccessfully scoured the universe for computer readable files of
  811. % town names, lat/lon and populations. They weren't available, despite
  812. % all the population planning that is done by organisations like the UN.
  813. % Presumably planning is still done with pencils and erasers. The
  814. % hardcopy available (several hundred pages), which indeed does have
  815. % all the info needed, was dual language Fr/Eng and in a format and
  816. % range of fonts designed to outwit any scanning hardware/software
  817. % combination known to man. Apparently this hardcopy was produced without
  818. % any computer intervention as there is no trace of the original data.
  819. %
  820. % The author of Traksat, Paul Traufler kindly offered his traksat.cty
  821. % file for non-commercial use, but this list does not have a method
  822. % for ranking the cities. We've put the problem off till a later
  823. % version of the program. If anyone would like to go through
  824. % Paul's file of 1690 cites and rank them in importance from
  825. % say 1..5 in a way that's compatible with Paul's planned future
  826. % use of the file, and send it to us, we would be very happy indeed.
  827.  
  828. %--------------------------------------
  829. %Start of routines
  830. %--------------------------------------
  831. /setup_variables
  832. [
  833.     /lat_QTH            /lon_QTH    /QTH_name
  834.     /lat_center            /lon_center    /center_offset
  835.     /map_scale_deg            /scale_type
  836.     /landscape
  837.     /draw_letter_square_borders        /draw_letter_square_labels
  838.     /draw_number_square_borders        /draw_number_square_labels
  839.     /draw_compass_circumference        /draw_compass_spokes
  840.     /draw_outer_border
  841.     /DXCC_callsigns
  842. ] def
  843.  
  844. /process_options_manual
  845. {
  846.     az_dict /scale_type known
  847.     {
  848.         scale_type
  849.         {
  850.         /kms_per_cm map_scale_deg def
  851.         } if
  852.     } if
  853. }def
  854.  
  855. /process_options
  856. {
  857.   /vno 0 def
  858.   options
  859.   {
  860.     dup type
  861.     {
  862.       dup /stringtype eq
  863.       {
  864.     pop
  865.     setup_variables vno get dup
  866.     az_dict exch known
  867.     {
  868.       dup cvx exec type /stringtype eq
  869.       {
  870.         exch def exit
  871.       }{
  872.         pop exit
  873.       } ifelse
  874.     }{
  875.       exch def exit
  876.     } ifelse
  877.       } if
  878.  
  879.       dup /booleantype eq
  880.       {
  881.     pop
  882.     setup_variables vno get dup
  883.     az_dict exch known
  884.     {
  885.       dup cvx exec type /booleantype eq
  886.       {
  887.         exch def exit
  888.       }{
  889.         pop exit
  890.       } ifelse
  891.     }{
  892.       exch def exit
  893.     } ifelse
  894.       } if
  895.  
  896.       dup /integertype eq
  897.       {
  898.                 pop cvr /realtype
  899.       } if
  900.  
  901.       /realtype eq
  902.       {
  903.     setup_variables vno get dup
  904.     az_dict exch known
  905.     {
  906.       dup cvx exec type /realtype eq
  907.       1 index cvx exec type /integertype eq or
  908.       {
  909.         exch def exit
  910.       }{
  911.         pop exit
  912.       } ifelse
  913.     }{
  914.       exch def exit
  915.     } ifelse
  916.       } if
  917.     } loop
  918.  
  919.     /vno vno 1 add    def
  920.     setup_variables length vno eq { exit } if
  921.   } forall
  922.  
  923.   az_dict /scale_type known
  924.   {
  925.     scale_type
  926.     {
  927.       /kms_per_cm  map_scale_deg def
  928.     } if
  929.   } if
  930.  
  931.   DXCC_callsigns not
  932.   {
  933.     /dxcc_info Cntry  def
  934.   } if
  935. } def
  936.  
  937.  
  938. %--------------------------------------
  939. % Printer problems - weird and otherwise
  940. /setup_specific
  941. {
  942.  
  943. % The ghostscript3.2.8 printer driver for the Color HP DJ550c gives the wrong
  944. % clippath for the printable region. The driver for this printer ignores
  945. % the 1/4" or so of paper at the end of the page that the rollers need
  946. % to hold the paper. The clippath is used to locate labels currently
  947. % at the bottom left of the page and the Title. It is also used to determine
  948. % font size.
  949.  
  950. % If your printer has similar problems, modify this routine for your
  951. % printer and send it to us (address above)
  952.  
  953.     /printer_fiddle {} def % your routine
  954.     % Default routine to modify the the values of LLx LLy URx URy
  955.     % returned from the bounding box of clippath. Several Ghostscript
  956.     % printer drivers (cdj500 and Epson) are known to give erronious
  957.     % values.
  958.     % It is executed in "setup_dimensions"
  959.  
  960. statusdict /product get (Ghostscript) search    % are we running Ghostscript?
  961.     {
  962.         pop pop pop
  963.         %the devicename call changed at gs3xx
  964.         currentdevice revision 300 lt    {devicename}{.devicename} ifelse
  965.         {
  966.              dup (cdj550) eq    % are we outputting for a cdj550c ?
  967.             {
  968.                 /printer_fiddle
  969.                 landscape
  970.                 {
  971.                     % fix clippath for landscape mode
  972.                     (landscape clippath fix for cdj550 \n) print_notice
  973.                     { 4 -1 roll 0.28 cm add 4 1 roll }
  974.                 }
  975.                 {
  976.                     % fix clippath for portrait mode
  977.                     (portrait clippath fix for HP DeskJet 550 \n) print_notice
  978.                     { 3 -1 roll 0.28 cm add 3 1 roll }
  979.                 } ifelse
  980.                 def
  981.                 % also do gamma correction
  982.                 (gamma correction for HP DeskJet 550 \n) print_notice
  983.                 { 0.2 exp } dup dup currenttransfer setcolortransfer
  984.                 pop exit
  985.             } if % cdj550
  986.  
  987.             dup (djet500) eq    % outputting to a HP Deskjet 500 ?
  988.             {
  989.                 % this gives a better grey scale than the default screen I think
  990.                 60.0 45.0
  991.                 {
  992.                     abs exch abs 2 copy add 1 gt
  993.                     { 1 sub dup mul exch 1 sub dup mul add 1 sub }
  994.                     { dup mul exch dup mul add 1 exch sub } ifelse
  995.                 } setscreen
  996.                 (grey scale correction for HP DeskJet 500 \n) print_notice
  997.                 { 2 exp } settransfer
  998.                 pop exit
  999.             } if %djet500
  1000.  
  1001.  
  1002.             % The epson driver gives wrong values for the clippath, so a
  1003.             % simillar 'printer fiddle' as the cdj550 is needed here.
  1004.             % We've found no problems with the (limited number of)
  1005.             % other drivers we've tried (add them here and send them to us).
  1006.  
  1007.             pop exit
  1008.         } loop    % all printers
  1009.     } %if Ghostscript
  1010.     {
  1011.         pop
  1012.     } ifelse % not Ghostscript
  1013.  
  1014.  
  1015. %Do gamma correction for color PostScript printers
  1016.  
  1017. %A word or two about gamma correction
  1018. %(only for those outputing to color printers).
  1019.  
  1020. %    A printer gives a brightness that is linearly dependant on input
  1021. %(much asyou would expect), i.e if you send {1,0,0} setrgbcolor
  1022. %to the printer , itwill produce a red that is twice as bright
  1023. %(measured presumably in electric field) aswill sending
  1024. %{0.5,0,0} setrgbcolor. A screen however, due to the physics
  1025. %of phosphors, will give output proportional to input^^gamma,
  1026. %where 2.2<gamma<2.5, i.e. the output increases faster than
  1027. %linearity. Since thebrightness at red =0 and red =1 are
  1028. %normalised for both printer and screen, the difference in
  1029. %output on the two devices will be noticedat mid-intensity
  1030. %output. The printer output will be darker than the screen.
  1031. %Thus the color lightblue as used here ({0.33,0.33,1} setrgbcolor),
  1032. %which is the default lake color, looks skyblue on a screen,
  1033. %but dark blue on a printer.
  1034. %
  1035. %    So there's a printer convention and a screen convention.
  1036. %No attempt has been made to make the output colors device
  1037. %independant. You sendyour output device the instructions
  1038. %and take what you get. If you want thecolor on the printer
  1039. %to look the same as the color on the screen preview you
  1040. %can do a gamma correction. The problem is to detect whether
  1041. %you need to correct or not. There isn't any way (that we know
  1042. %of) for the code to know whether it'srunning on a color
  1043. %printer or a screen, or whether a color printer has the
  1044. %color or the B&Wcartridge installed. 
  1045. %
  1046. %    The way we've chosen to handle this is to ask the name
  1047. %of the output device ("/product"). If it's a non Postscript
  1048. %printer and you are using Ghostscript then you look up the
  1049. %Ghostscript manualto find that the HP DeskJet 550C is called
  1050. %a cdj550. If it's a real Postscriptprinter (e.g. HP DeskJet
  1051. %1200C or Tektronics Phaser IISDX) then you look upthe printer
  1052. %manualto see what string will be returned when you ask for
  1053. %the "/product"string. Once you've found this, duplicate,
  1054. %for your printer, an appropriate piece of codefound below
  1055. %(and send it to us so we can put it in the ourcode for future
  1056. %releases). You have to chose a value for inverse gamma
  1057. %(suggest 0.3-0.4) that gives the same color on the printer
  1058. %as you see on your screen. A test would be the light blue
  1059. %used to fill lakes. To make the printer output a lighter
  1060. %color, chose a smaller number for inverse gamma.
  1061. %
  1062.  
  1063.     statusdict /product get (DeskJet 1200C) eq
  1064.     {
  1065.         % Gamma correction for DeskJet 1200C
  1066.         (gamma correction for DeskJet 1200C \n) print_notice
  1067.         { 0.333 exp } dup dup currenttransfer setcolortransfer
  1068.     } if
  1069.  
  1070.     statusdict /product get (Phaser IISDX) eq
  1071.     {
  1072.         % Gamma correction for color printers
  1073.         (gamma correction for Phaser IISDX \n) print_notice
  1074.         { 0.333 exp } dup dup currenttransfer setcolortransfer
  1075.     } if
  1076.  
  1077. } def
  1078.  
  1079. %--------------------------------------
  1080. /print_notice    % will send notices to stdout if send_notices true
  1081. {
  1082.     send_notices { print flush }{ pop } ifelse
  1083. } bind def
  1084.  
  1085. %--------------------------------------
  1086. /verbose_notice    % will send notices to stdout if send_notices & verbose true
  1087. {
  1088.     send_notices verbose and { print flush }{ pop } ifelse
  1089. } bind def
  1090.  
  1091. %--------------------------------------
  1092.  
  1093. % Print the Amateur Call (or any other field in dxcc_info).
  1094. % To change the output (eg if you want time zones instead of Amateur Prefix),
  1095. % change the field in dxcc_info
  1096. % syntax --    DXCC_ARRAY Print_Call -
  1097. /Print_Call
  1098. {
  1099.     /Dxcc_array exch def
  1100.     Dxcc_array LAT get dup
  1101.     Dxcc_array LON get dup
  1102.  
  1103.     % don't print calls with invalid lat/lon
  1104.     NO_LATLON eq 3 -1 roll NO_LATLON eq or not
  1105.     {
  1106.         gc
  1107.         /bearing exch def
  1108.         /distance exch def
  1109.  
  1110.         circle_dxcc
  1111.         {    % required to print in circular text
  1112.             /bearing
  1113.             bearing 450.0 exch sub dup 360.0 ge {360.0 sub} if
  1114.             def
  1115.  
  1116.  
  1117.             0 0 moveto
  1118.             % call outside printing for lower hemisphere
  1119.             % & inside printing for upper hemisphere
  1120.             Dxcc_array dxcc_info get dxcc_font_size bearing distance
  1121.             bearing 0.0 gt bearing 180.0 lt and
  1122.             {
  1123.                 % tweek distance so that label is in middle
  1124.                 dxcc_font_size 2 div sub
  1125.                 outsidecircletext
  1126.             }{
  1127.                 % tweek distance so that label is in middle
  1128.                 dxcc_font_size 2 div add
  1129.                 insidecircletext
  1130.             } ifelse
  1131.         }{
  1132.             distance bearing distance_bearing2xy moveto
  1133.             Dxcc_array dxcc_info get dup stringwidth pop 2 div neg
  1134.             dxcc_font_size neg rmoveto
  1135.             %dxcc_color setrgbcolor
  1136.             outlineshow
  1137.         } ifelse
  1138.     }{
  1139.         pop pop
  1140.     } ifelse
  1141. }def
  1142.  
  1143. %--------------------------------------
  1144. /plot_waypoint
  1145. {
  1146.  
  1147.     rover_font findfont rover_font_size scalefont setfont
  1148.  
  1149.     %draw line
  1150.     newpath
  1151.     black setrgbcolor
  1152.     2.5 atom mul setlinewidth
  1153.     0 0 moveto
  1154.     waypoint_distance waypoint_bearing distance_bearing2xy lineto % waypoint location
  1155.     stroke
  1156.  
  1157.     %draw circle at waypoint
  1158.     newpath
  1159.     waypoint_distance waypoint_bearing distance_bearing2xy % waypoint x,y
  1160.     10 atom mul %radius of circle
  1161.     0 360 arc
  1162.     closepath
  1163.     stroke
  1164.  
  1165.  
  1166.  
  1167.  
  1168.  
  1169.     %show_bearing
  1170.  
  1171.                 %go to half way out
  1172.                 %divide distance by half, and keep copy of dist
  1173.                 waypoint_distance 2 div waypoint_bearing
  1174.                 distance_bearing2xy moveto    %go there
  1175.                 %convert compass origin and direction of rotation to cartesian system
  1176.                 waypoint_bearing neg 90 add rotate
  1177.                 0 10 atom mul rmoveto
  1178.                 waypoint_bearing cvi temp_string cvs dup stringwidth pop 2 div neg 0 rmoveto show
  1179.                 0 10 atom mul neg rmoveto
  1180.                 waypoint_bearing 90 sub rotate
  1181.  
  1182.     %show_distance
  1183.                 waypoint_distance 2 div bearing distance_bearing2xy moveto    %go there
  1184.                 waypoint_bearing neg 90 add rotate
  1185.                 0 30 atom mul neg rmoveto
  1186.                 %convert deg to km, find string width, offset, show
  1187.                 waypoint_distance deg2km cvi temp_string cvs dup stringwidth pop 2 div neg 0 rmoveto show
  1188.                 ( km) show
  1189.                 0 30 atom mul rmoveto
  1190.                 waypoint_bearing 90 sub rotate
  1191.  
  1192. }def % plot_waypoint
  1193. %--------------------------------------
  1194. /extract_GLL
  1195. {
  1196. %GLL=Geographic Lat Lon
  1197. %on stack - a string like (4130.34,N,7135.42,W)
  1198. % pop % one line dummy routine to pop string off stack - for testing
  1199. %pstack (extract_GLL \n) print_notice
  1200. /error 0 def
  1201.  
  1202. (,) search
  1203.     {
  1204.         %pstack (extract_GLL \n) print_notice
  1205.         %on stack (4130.34), then (,) then (N,7135.42,W)
  1206.         exch pop % get rid of (,)
  1207.         cvr dup    cvi 100 idiv %41
  1208.         /lat_GLL exch def
  1209.         100 div lat_GLL sub %0.3034
  1210.         10 mul 6 div lat_GLL add /lat_GLL exch def
  1211.         %pop
  1212.  
  1213.         %N or S?
  1214.         (,) search
  1215.         {
  1216.             %on stack: (N) or (S), then (,) then (7135.42,W)
  1217.             exch pop % pop (,)
  1218.             {
  1219.  
  1220.             dup    (N) eq
  1221.                 {
  1222.                     %pstack (got here N \n) print_notice
  1223.                     pop % (N)
  1224.                     %lat_GLL = (lat_GLL is N \n) print_notice
  1225.                     exit
  1226.                 } if % N do nothing
  1227.  
  1228.             dup (S) eq
  1229.                 {
  1230.                      %pstack (got here S \n) print_notice
  1231.                     pop % (S)
  1232.                     % make -ve for southern hemisphere
  1233.                     lat_GLL neg /lat_GLL exch def
  1234.                     %lat_GLL = (lat_GLL is S \n) print_notice
  1235.                     exit
  1236.                 } if % S invert sign
  1237.  
  1238.             /error -1 def
  1239.             /bad_string exch def
  1240.             (bad GLL lat string: ) print bad_string print  ( - expect N or S \n) print
  1241.             exit
  1242.             }loop % N,S, or ?
  1243.         } % if of ifelse, (,) found
  1244.         {
  1245.         /error -1 def
  1246.         pstack (bad GLL lat string, expect `,' before N or S \n) print
  1247.         pop
  1248.         } ifelse %(,) not found ,
  1249.     }% if of ifelse
  1250.     {
  1251.         /error -1 def
  1252.         pstack (bad GLL lat string, expect `,' somewhere \n) print
  1253.         pop
  1254.     } ifelse %(,) not found in string
  1255.  
  1256.  
  1257. (,) search
  1258.     {
  1259.         %on stack (7135.42) (,) (W)
  1260.         exch pop % get rid of (,)
  1261.         %pstack (lon_GLL \n) print_notice
  1262.         cvr dup    cvi 100 idiv %71
  1263.         /lon_GLL exch def
  1264.         100 div lon_GLL sub %0.3542
  1265.         10 mul 6 div lon_GLL add /lon_GLL exch def
  1266.  
  1267.         %E or W?
  1268.         %on stack: (E) or (W)
  1269.         %(GLL: E or W? \n) print_notice
  1270.         % or if passing stuff from BWC then the string will be
  1271.         % (W,175,T,185,M,252.5,N,####)
  1272.  
  1273.          { % loop
  1274.  
  1275.         (,) search
  1276.         {
  1277.             % pstack (found BWC type string in GLL \n) print_notice
  1278.             % we've found a longer string presumably from BWC
  1279.             % find the (E) or (W) and leave the rest on the stack
  1280.             % on stack (W) (,) (175,T,185,M,252.5,N,####)
  1281.             exch pop % pop (,)
  1282.         } if
  1283.  
  1284.         dup    (E) eq
  1285.             {
  1286.                 pop % (E)
  1287.                 %lon_GLL = (lon_GLL is E \n) print_notice
  1288.                 exit
  1289.             } if % (E) do nothing
  1290.  
  1291.         dup    (W) eq
  1292.             {
  1293.                 pop % (W)
  1294.                 % make -ve for western hemisphere
  1295.                 lon_GLL neg /lon_GLL exch def
  1296.                 %lon_GLL = (lon_GLL is W \n) print_notice
  1297.                 exit
  1298.             } if % (W) invert sign of lon
  1299.  
  1300.             /error -1 def
  1301.             /bad_string exch def
  1302.             (bad GLL lon string: ) print bad_string print  ( - expect E or W \n) print
  1303.             exit
  1304.         } loop % through E,W or error string
  1305.     }% if of ifelse (,) found
  1306.     {
  1307.         /error -1 def
  1308.         /bad_string exch def
  1309.         pstack (bad GLL lon string: ) print bad_string print ( - expect `,' \n) print
  1310.         pop
  1311.     } ifelse %(,) not found in string
  1312.  
  1313.  
  1314.     error 0 eq
  1315.     {
  1316.     lat_GLL /lat_QTH exch def
  1317.     lon_GLL /lon_QTH exch def
  1318.     %lat_QTH = (lat_QTH \n) print_notice
  1319.     %lon_QTH = (lon_QTH \n) print_notice
  1320.     %pstack (heads up \n) print_notice %check stack, should be empty
  1321.  
  1322.     %Have to get lat_QTH, lon_QTH to the outside world
  1323.     %We're currently down inside a save/restore
  1324.     %See the write up near the string "Bigbang restore"
  1325.  
  1326.     } %if of ifelse - if we have a new QTH
  1327.     {
  1328.         (Error in nmea GLL statement, lat/lon not recovered \n) print_notice
  1329.     }ifelse
  1330.  
  1331. } def
  1332.  
  1333.  
  1334. %--------------------------------------
  1335. /extract_BOD
  1336. {
  1337. % Bearing Origin to Dest
  1338. %pstack
  1339. %(extract_BOD - not implemented \n) print_notice
  1340. ($GP data type BOD - not implemented \n) print_notice
  1341. pop
  1342. } def
  1343.  
  1344. %--------------------------------------
  1345. /extract_BWC
  1346. {
  1347. %    Bearing to waypoint along great circle
  1348. %pstack
  1349. %(extract_BWC \n) print_notice
  1350. %pop % dummy routine for testing call.
  1351.  
  1352. /error 0 def
  1353. /BWC_distance -1 def
  1354.  
  1355. % on stack string like (235959,4359.00,N,7459.00,W,175,T,185,M,252.5,N,####)
  1356.  
  1357. (,) search
  1358.     {
  1359.         % on stack (235959) (,) (4359.00,N,7459.00,W,175,T,185,M,252.5,N,####)
  1360.         exch pop % (,)
  1361.         cvr 10000 div
  1362.         dup cvi /hour exch def
  1363.         %hour = (BWC_hour \n) print_notice
  1364.         hour sub 100 mul cvi /min exch def
  1365.         %min = (BWC_min \n) print_notice
  1366.         % on stack (4359.00,N,7459.00,W,175,T,185,M,252.5,N,####)
  1367.         extract_GLL
  1368.  
  1369.         % on stack string like (175,T,185,M,252.5,N,####)
  1370.  
  1371.         %pstack (BWC string 2\n) print_notice
  1372.  
  1373.         (,) search
  1374.         {
  1375.             % on stack string like (175) (,) (T,185,M,252.5,N,####)
  1376.             exch pop % pop (,)
  1377.             cvr /BWC_bearing exch def
  1378.             %BWC_bearing = (BWC_bearing \n) print_notice
  1379.  
  1380.             (T,) search
  1381.             {
  1382.                 % on stack string like () (T,) (185,M,252.5,N,####)
  1383.                 pop % pop ()
  1384.                 pop % pop (T,)
  1385.                 %(BWC_bearing is True \n) print_notice
  1386.  
  1387.                 (M,) search
  1388.                 {
  1389.                     % on stack string like (185,) (M,) (252.5,N,####)
  1390.                     % the first two represent the magnetic bearing which we aren't interested in
  1391.                     pop pop
  1392.                     (,) search
  1393.                     {
  1394.                         % on stack string like (252.5) (,) (N,####)
  1395.                         exch pop % pop (,)
  1396.                         cvr /BWC_distance exch def
  1397.                         %BWC_distance = (BWC_distance \n) print_notice
  1398.  
  1399.                         (,) search
  1400.                         {
  1401.                             % on stack string like (N) (,) (####)
  1402.                             exch pop % pop (,)
  1403.                             exch pop % (####)
  1404.  
  1405.                             { % loop
  1406.                                 dup (N) eq
  1407.                                 {
  1408.                                     % Nautical miles
  1409.                                     %(BWC distance is in nautical miles \n) print_notice
  1410.                                     % turn into degrees
  1411.                                     BWC_distance NM2deg /BWC_distance exch def
  1412.                                     pop % (N)
  1413.                                     exit
  1414.                                 } if
  1415.  
  1416.                                 dup (M) eq
  1417.                                 {
  1418.                                     % Statute miles
  1419.                                     %(BWC distance is in Statute miles \n) print_notice
  1420.                                     % turn into degrees
  1421.                                     BWC_distance M2deg /BWC_distance exch def
  1422.                                     pop % (M)
  1423.                                     exit
  1424.                                 } if
  1425.  
  1426.                                 /error -1 def
  1427.                                 /bad_string exch def
  1428.                                 (bad BWC distance units string: ) print bad_string print  ( - expect N or M \n) print
  1429.                                 pop
  1430.                                 exit
  1431.                             } loop
  1432.  
  1433.                         } % if of ifelse
  1434.                         {
  1435.                             /error -1 def
  1436.                             /bad_string exch def
  1437.                             pstack (bad BWC string: ) print bad_string print ( - expect `,' after N/M \n) print
  1438.                         } ifelse
  1439.                     }
  1440.                     {
  1441.                         /error -1 def
  1442.                         /bad_string exch def
  1443.                         pstack (bad BWC string: ) print bad_string print ( - expect `M,' \n) print
  1444.                     } ifelse
  1445.                  }
  1446.                 {
  1447.                     /error -1 def
  1448.                     /bad_string exch def
  1449.                     pstack (bad BWC string: ) print bad_string print ( - expect `M,' \n) print
  1450.                 } ifelse
  1451.              }
  1452.             {
  1453.                 /error -1 def
  1454.                 /bad_string exch def
  1455.                 pstack (bad BWC string: ) print bad_string print ( - expect `T,' \n) print
  1456.             } ifelse
  1457.          }% if of ifelse (,) found
  1458.         {
  1459.             /error -1 def
  1460.             /bad_string exch def
  1461.             pstack (bad BWC string: ) print bad_string print ( - expect `,' \n) print
  1462.         }ifelse % (,) not found
  1463.      }    % if of ifelse, (,) found
  1464.     {
  1465.         /error -1 def
  1466.         /bad_string exch def
  1467.         pstack (bad BWC string: ) print bad_string print ( - expect `,' \n) print
  1468.     }ifelse % (,) not found
  1469.  
  1470.     error 0 eq BWC_distance -1 eq not and
  1471.     {
  1472.     BWC_bearing /waypoint_bearing exch def
  1473.     BWC_distance /waypoint_distance exch def
  1474.     %waypoint_bearing = (waypoint_bearing \n) print_notice
  1475.     %waypoint_distance = (waypoint_distance \n) print_notice
  1476.     %pstack (heads up \n) print_notice %check stack, should be empty
  1477.  
  1478.     plot_waypoint
  1479.  
  1480.     %Have to get to the outside world
  1481.     %We're currently down inside a save/restore
  1482.     %See the write up near the string "Bigbang restore"
  1483.  
  1484.     } %if of ifelse - if we have a valid Bearing/Dist
  1485.     {
  1486.         (Error in nmea BWC statement, bearing/dist not recovered \n) print_notice
  1487.     }ifelse
  1488.  
  1489. } def
  1490.  
  1491. %--------------------------------------
  1492. /annotation_fields
  1493. [
  1494.     () 0.0 0.0
  1495. ] def
  1496.  
  1497. /extract_annotation
  1498. % Parse the line of input that we suspect to be an annotation
  1499. {
  1500.     {    % look for annotation string
  1501.         (:) search
  1502.         {
  1503.             annotation_fields 0 3 -1 roll put pop
  1504.         }{
  1505.             pop exit    % bad line
  1506.         } ifelse
  1507.  
  1508.         % Latitude. Convert N to positive real and S to negative real
  1509.         (:) search
  1510.         {
  1511.             (N) search
  1512.             {
  1513.                 token
  1514.                 {
  1515.                     dup type dup /integertype eq exch /realtype eq or
  1516.                     {
  1517.                         cvr annotation_fields 1 3 -1 roll
  1518.                         dup 90.0 le    % check for legal value
  1519.                         {
  1520.                             put
  1521.                         }{
  1522.                             pop NO_LATLON put
  1523.                         } ifelse
  1524.                         pop pop pop pop
  1525.                     }{
  1526.                         pop pop pop pop pop exit % bad LAT
  1527.                     } ifelse
  1528.                 }{
  1529.                     pop pop pop exit
  1530.                 } ifelse
  1531.             }{
  1532.                 (S) search
  1533.                 {
  1534.                     token
  1535.                     {
  1536.                         dup type dup /integertype eq exch /realtype eq or
  1537.                         {
  1538.                             cvr annotation_fields 1 3 -1 roll neg
  1539.                             dup -90.0 ge    % check for legal value
  1540.                             {
  1541.                                 put
  1542.                             }{
  1543.                                 pop NO_LATLON put
  1544.                             } ifelse
  1545.                             pop pop pop pop
  1546.                         }{
  1547.                             pop pop pop pop pop exit    % bad LAT
  1548.                         } ifelse
  1549.                     }{
  1550.                         pop pop pop exit
  1551.                     } ifelse
  1552.                 }{
  1553.                     annotation_fields 1 NO_LATLON put pop
  1554.                 } ifelse
  1555.             } ifelse
  1556.         }{
  1557.             pop exit
  1558.         } ifelse
  1559.  
  1560.         % Longitude. Convert E to positive real and W to negative real
  1561.  
  1562.         (E) search
  1563.         {
  1564.             token
  1565.             {
  1566.                 dup type dup /integertype eq exch /realtype eq or
  1567.                 {
  1568.                     cvr annotation_fields 2 3 -1 roll
  1569.                     dup 180.0 le    % check for legal value
  1570.                     {
  1571.                         put
  1572.                     }{
  1573.                         pop NO_LATLON put
  1574.                     } ifelse
  1575.                     pop pop pop
  1576.                 }{
  1577.                     pop pop pop pop exit    % bad LON
  1578.                 } ifelse
  1579.             }{
  1580.                 pop pop exit
  1581.             } ifelse
  1582.         }{
  1583.             (W) search
  1584.             {
  1585.                 token
  1586.                 {
  1587.                     dup type dup /integertype eq exch /realtype eq or
  1588.                     {
  1589.                         cvr annotation_fields 2 3 -1 roll neg
  1590.                         dup -180.0 ge    % check for legal value
  1591.                         {
  1592.                             put
  1593.                         }{
  1594.                             pop NO_LATLON put
  1595.                         } ifelse
  1596.                     pop pop pop
  1597.                     }{
  1598.                         pop pop pop pop exit    % bad LON
  1599.                     } ifelse
  1600.                 }{
  1601.                     pop pop exit
  1602.                 } ifelse
  1603.             }{
  1604.                 annotation_fields 2 NO_LATLON put pop
  1605.             } ifelse
  1606.         } ifelse
  1607.         % Uncomment to print each array as it is parsed (We only get here on good lines)
  1608.         % annotation_fields { = } forall
  1609.         annotation_fields Print_annotation
  1610.         exit
  1611.     } loop
  1612. } def
  1613.  
  1614. %--------------------------------------
  1615. /Print_annotation
  1616. {
  1617.   {} forall
  1618.  
  1619.   dup 1 index
  1620.  
  1621.   % don't print calls with invalid lat/lon
  1622.   NO_LATLON eq exch NO_LATLON eq or not
  1623.   {
  1624.     gsave
  1625.       2 copy 5 2 roll
  1626.  
  1627.       % write label
  1628.       lat_lon2xy moveto
  1629.       annot_font findfont annot_font_size scalefont setfont
  1630.       dup stringwidth pop 2 div neg
  1631.       atom 8 mul
  1632.       rmoveto
  1633.  
  1634.     % This erases the screen around the annotation (creates a white
  1635.     % background), so that the string is readable
  1636.     % We write the character outlines with a very thick white pen first.
  1637.  
  1638.       currentpoint 1.0 setgray  25 atom mul setlinewidth
  1639.       2 index true charpath stroke moveto
  1640.  
  1641.       annot_color setrgbcolor show
  1642.  
  1643.       % draw a blob here
  1644.       newpath lat_lon2xy atom 6 mul 0 360 arc fill
  1645.  
  1646.  
  1647.     grestore
  1648.   }{
  1649.     pop pop pop
  1650.   } ifelse
  1651. } def
  1652.  
  1653. %--------------------------------------
  1654. % Parse the line of input that we suspect to be a dxcc entry
  1655.  
  1656. /Dxcc_fields % This is the form of the 'DXCC' array
  1657. [
  1658.     () () 0 () () 0 0.0 0.0 () ()
  1659. ] def
  1660.  
  1661. % These are the fields within the array
  1662. /Am_Call    0 def
  1663. /Cntry        1 def
  1664. /Cont        2 def
  1665. /ITUzns        3 def
  1666. /CQzns        4 def
  1667. /Time        5 def
  1668. /LAT        6 def
  1669. /LON        7 def
  1670. /ITUcall    8 def
  1671. /Am_more    9 def
  1672.  
  1673. /dxcc_info Am_Call def    % this is the default field printed from DXCC entry
  1674.             % all of the above fields are strings,
  1675.             % (except LAT, LON). Any of the string fields can be
  1676.             % substituted for Am_Call for output.
  1677.  
  1678. /big_D false def    %needs to be defined before first entry into extract_dxcc
  1679.  
  1680. %error flags
  1681. /NULL_FIELD    -1 def
  1682. /NO_TIME    -100 def
  1683. /NO_LATLON    -200.0 def
  1684.  
  1685.  
  1686. /extract_dxcc
  1687. {
  1688.     { %loop
  1689.         big_D    % if symbol is DXCC and not dxcc
  1690.         {
  1691.             %(big D \n) print
  1692.             %(special country 2 \n)print
  1693.             dxcc_special_country_2
  1694.         } if
  1695.  
  1696.     % look for primary amateur call sign
  1697.     (:) search
  1698.         {
  1699.         (*) search
  1700.             {
  1701.                 pop pop pop pop pop
  1702.                 %(deleted call) print
  1703.                 exit    % deleted call
  1704.             } if % *
  1705.         Dxcc_fields Am_Call 3 -1 roll put pop
  1706.         }
  1707.         {
  1708.             pop
  1709.             %(bad line \n) print
  1710.             exit    % bad line
  1711.         } ifelse
  1712.  
  1713.     % look for country name
  1714.     (:) search
  1715.         {
  1716.             %(country name \n) print pstack
  1717.             Dxcc_fields Cntry 3 -1 roll put pop
  1718.         }
  1719.         {
  1720.             pop
  1721.             %(bad line 2) print
  1722.             exit % bad line
  1723.         } ifelse
  1724.  
  1725.     % look for continent and choose one of 7
  1726.     (:) search
  1727.         {
  1728.         dup length 2 ge { 0 2 getinterval } if (EuAfAsOcAnNASA) exch search
  1729.             {
  1730.             length 2 idiv
  1731.             exch length 0 eq
  1732.                 {
  1733.                 pop -1 % null continent
  1734.                 %(bad line 3\n) print pstack
  1735.                 } if
  1736.             %(found continent \n) print
  1737.             Dxcc_fields Cont 3 -1 roll put pop pop
  1738.             }
  1739.             {
  1740.             pop pop pop exit
  1741.             } ifelse
  1742.         } % ifelse (:) found
  1743.         {
  1744.         pop
  1745.         %(bad line 4) print
  1746.         exit        % bad line
  1747.         } ifelse % (:) not found
  1748.  
  1749.     % ITU zone. This can be numbers in the form "21-24",
  1750.     % so we keep it as a string, rather than numbers
  1751.     % so we can further break it down if necessary
  1752.     (:) search
  1753.         {
  1754.             Dxcc_fields ITUzns 3 -1 roll put pop
  1755.         }{
  1756.             pop
  1757.             %(bad line 5) print
  1758.             exit % bad line
  1759.         } ifelse
  1760.  
  1761.     % CQ zones. This can be numbers in the form "21-24",
  1762.     % so we keep it as a string.
  1763.     % We can further break it down if necessary
  1764.     (:) search
  1765.         {
  1766.             Dxcc_fields CQzns 3 -1 roll put pop
  1767.         }{
  1768.             pop
  1769.             %(bad line 6) print
  1770.             exit        % bad line
  1771.         } ifelse
  1772.  
  1773.  
  1774.     % Time (from UTC). Convert to a real
  1775.     (:) search
  1776.         {
  1777.         Dxcc_fields Time 3 -1 roll token
  1778.             {
  1779.             exch pop
  1780.             dup type dup /integertype eq exch /realtype eq or
  1781.             % should be an int or a real
  1782.                 {
  1783.                 cvr put pop
  1784.                 }{
  1785.                 pop pop pop pop
  1786.                 %(bad line 7) print
  1787.                 exit        % bad zone, drop entry
  1788.                 } ifelse
  1789.             }{
  1790.             NO_TIME put pop    % no zone supplied
  1791.             } ifelse
  1792.         }
  1793.         {
  1794.         pop exit
  1795.         } ifelse
  1796.  
  1797.     % Latitude. Convert N to positive real and S to negative real
  1798.     (:) search
  1799.         {
  1800.         (N) search
  1801.             {
  1802.             token
  1803.                 {
  1804.                 dup type dup /integertype eq exch /realtype eq or
  1805.                     {
  1806.                     cvr    Dxcc_fields LAT 3 -1 roll
  1807.                     dup 90.0 le        % check for legal value
  1808.                         {
  1809.                         put
  1810.                         }{
  1811.                         pop NO_LATLON put
  1812.                         } ifelse
  1813.                     pop pop pop pop
  1814.                     }{
  1815.                     pop pop pop pop pop exit    % bad LAT
  1816.                     } ifelse
  1817.                 }{
  1818.                 pop pop pop exit
  1819.                 } ifelse
  1820.             }{
  1821.             (S) search
  1822.                 {
  1823.                 token
  1824.                     {
  1825.                     dup type dup /integertype eq exch /realtype eq or
  1826.                         {
  1827.                         cvr    Dxcc_fields LAT 3 -1 roll neg
  1828.                         dup -90.0 ge    % check for legal value
  1829.                             {
  1830.                             put
  1831.                             }{
  1832.                             pop NO_LATLON put
  1833.                             } ifelse
  1834.                         pop pop pop pop
  1835.                         }{
  1836.                         pop pop pop pop pop exit    % bad LAT
  1837.                         } ifelse
  1838.                     }{
  1839.                     pop pop pop exit
  1840.                     } ifelse
  1841.                 }{
  1842.                 Dxcc_fields LAT NO_LATLON put pop
  1843.                 } ifelse
  1844.             } ifelse
  1845.         }{
  1846.         pop exit
  1847.         } ifelse
  1848.  
  1849.     % Longitude. Convert E to positive real and W to negative real
  1850.     (:) search
  1851.         {
  1852.         (E) search
  1853.             {
  1854.             token
  1855.                 {
  1856.                 dup type dup /integertype eq exch /realtype eq or
  1857.                     {
  1858.                     cvr    Dxcc_fields LON 3 -1 roll
  1859.                     dup 180.0 le    % check for legal value
  1860.                         {
  1861.                         put
  1862.                         }{
  1863.                         pop NO_LATLON put
  1864.                         } ifelse
  1865.                     pop pop pop pop
  1866.                     }{
  1867.                     pop pop pop pop pop exit    % bad LON
  1868.                     } ifelse
  1869.                 }{
  1870.                 pop pop pop exit
  1871.                 } ifelse
  1872.             }{
  1873.             (W) search
  1874.                 {
  1875.                 token
  1876.                     {
  1877.                     dup type dup /integertype eq exch /realtype eq or
  1878.                         {
  1879.                         cvr    Dxcc_fields LON 3 -1 roll neg
  1880.                         dup -180.0 ge    % check for legal value
  1881.                             {
  1882.                             put
  1883.                             }{
  1884.                             pop NO_LATLON put
  1885.                             } ifelse
  1886.                         pop pop pop pop
  1887.                         }{
  1888.                         pop pop pop pop pop exit    % bad LON
  1889.                         } ifelse
  1890.                     }{
  1891.                     pop pop pop exit
  1892.                     } ifelse
  1893.                 }{
  1894.                 Dxcc_fields LON NO_LATLON put pop pop
  1895.                 } ifelse
  1896.             } ifelse
  1897.         }{
  1898.         pop exit
  1899.         } ifelse
  1900.  
  1901.     % ITU Call assignment
  1902.     (:) search
  1903.         {
  1904.         Dxcc_fields ITUcall 3 -1 roll put pop
  1905.         }{
  1906.         %(bad line ITU call \n) print pstack
  1907.         pop exit        % bad line
  1908.         } ifelse
  1909.  
  1910.     % Final field is the additional amateur calls
  1911.     Dxcc_fields Am_more 3 -1 roll put
  1912.  
  1913.     % We only get here on good lines. Uncomment next line
  1914.     % to print each array as it is parsed
  1915.     %    Dxcc_fields { = } forall
  1916.  
  1917.     Dxcc_fields Print_Call
  1918.     exit
  1919.     } loop
  1920. } def
  1921.  
  1922. %--------------------------------------
  1923.  
  1924. /extract_band_mode
  1925. {
  1926. % a string will be on top of the stack.
  1927. % if band mode info is present - eg "20 CW" the line will be like
  1928. %
  1929. % 20 CW:1S:Spratly Is:As:50:26:+7:9N:112E:1S~:9M0
  1930. %
  1931. % otherwise the string on the stack will be like
  1932. %
  1933. % 1S:Spratly Is:As:50:26:+7:9N:112E:1S~:9M0
  1934. %
  1935. % get string in front of ":" and look for blank
  1936. %(extract_band_mode: entry string \n)print
  1937. dxcc_line
  1938. %pstack
  1939. (:) search
  1940.     {
  1941.     %have either country code or band/mode info
  1942.     %(looking for blank\n) print
  1943.     ( ) search % look for blank
  1944.         {    %band/mode info found
  1945.         %(found band_mode \n) print
  1946.         %pstack
  1947.         /band_worked false def    %initialise
  1948.         % should be a number then blank then mode eg "20 CW"
  1949.         % extract the number
  1950.         cvi % convert string representing freq into integer
  1951.         /dxcc_band_entry_found exch def    % variable for entry found in DXCC line
  1952.         %pstack
  1953.         dxcc_bands_plotted    %array of bands to be plotted, from az_ini.ps
  1954.             {
  1955.             dxcc_band_entry_found eq    %check the entry found
  1956.                 {
  1957.                 /band_worked true def    %if found set flag
  1958.                 %(band entry found\n) print
  1959.                 } if
  1960.             }forall % dxcc_bands
  1961.  
  1962.         %parse mode
  1963.         /mode_worked false def    % initialise
  1964.         %(mode \n) print
  1965.         pop % remove blank
  1966.         %pstack
  1967.         /dxcc_mode_entry_found exch def %the mode in the input line
  1968.         dxcc_modes_plotted    %the ones requested to plot in az_ini.ps
  1969.             {
  1970.             dxcc_mode_entry_found eq    % the ones in the dxcc.dat file
  1971.                 {
  1972.                 /mode_worked true def    % did we get a hit?
  1973.                 %(mode is to be plotted\n) print
  1974.                 } if
  1975.             }forall %dxcc_modes_plotted
  1976.  
  1977.         mode_worked band_worked and
  1978.             {
  1979.             % both band and mode are OK, so mark it in special mode
  1980.             dxcc_special_country
  1981.             }
  1982.             {
  1983.             % not a dxcc country to be specially marked
  1984.             dxcc_country
  1985.             } ifelse
  1986.         pop %remove colon
  1987.         %(going to extract_dxcc\n) print
  1988.         %pstack
  1989.         extract_dxcc
  1990.         } %found blank, ie band/mode info found in line
  1991.         {
  1992.         %(no blank found, not band mode pair\n) print
  1993.         % pop dismembered line
  1994.         pop pop pop
  1995.         % put back fresh copy
  1996.         dxcc_line
  1997.         %pstack
  1998.         % have a country code on top of stack
  1999.         extract_dxcc % do it whether we find an band/mode or not
  2000.         } ifelse % blank not found
  2001.     } % colon found
  2002.     {
  2003.     %(bad line, no :) print
  2004.     %pstack
  2005.     exit    % bad line
  2006.     } ifelse
  2007. } def
  2008.  
  2009.  
  2010. %--------------------------------------
  2011. % routine: Circular Text from the 'Blue Book'
  2012. % This prints text around a circle.
  2013. /outsidecircletext
  2014. { $circtextdict begin
  2015.     /radius exch def
  2016.     /centerangle exch def
  2017.     /ptsize exch def
  2018.     /str exch def
  2019.     /xradius radius ptsize 4 div add def
  2020.     gsave
  2021.     centerangle str findhalfangle
  2022.     add rotate
  2023.     str
  2024.     { /charcode exch def
  2025.         ( ) dup 0 charcode put
  2026.         outsideshowcharandrotate
  2027.     } forall
  2028.     grestore
  2029.     end
  2030. } def
  2031.  
  2032. %--------------------------------------
  2033. /insidecircletext
  2034.  { $circtextdict begin
  2035.     /radius exch def
  2036.     /centerangle exch def
  2037.     /ptsize exch def
  2038.     /str exch def
  2039.     /xradius radius ptsize 3 div sub def
  2040.     gsave
  2041.     centerangle str findhalfangle
  2042.     sub rotate
  2043.     str
  2044.     {
  2045.         /charcode exch def
  2046.         ( ) dup 0 charcode put
  2047.         insideshowcharandrotate
  2048.     } forall
  2049.     grestore
  2050.     end
  2051.  } def
  2052.  
  2053. %--------------------------------------
  2054. /$circtextdict 16 dict def
  2055. $circtextdict begin
  2056. /findhalfangle
  2057.     {
  2058.         stringwidth pop 2 div
  2059.         2 xradius mul pi mul div 360 mul
  2060.     } def
  2061.  
  2062. %--------------------------------------
  2063. /outsideshowcharandrotate
  2064.     {
  2065.         /char exch def
  2066.         /halfangle char findhalfangle def
  2067.         gsave
  2068.         halfangle neg rotate
  2069.         radius 0 translate
  2070.         -90 rotate
  2071.         char stringwidth pop 2 div neg
  2072.         0 moveto char outlineshow
  2073.         grestore
  2074.         halfangle 2 mul neg rotate
  2075.     } def
  2076.  
  2077. %--------------------------------------
  2078. /insideshowcharandrotate
  2079.     {
  2080.         /char exch def
  2081.         /halfangle char findhalfangle def
  2082.         gsave
  2083.         halfangle rotate
  2084.         radius 0 translate
  2085.         90 rotate
  2086.         char stringwidth pop 2 div neg
  2087.         0 moveto char outlineshow
  2088.         grestore
  2089.         halfangle 2 mul rotate
  2090.     } def
  2091.  
  2092. %--------------------------------------
  2093. /pi 3.1415923 def
  2094. end
  2095. % end of circle routine
  2096.  
  2097.  
  2098. %--------------------------------------
  2099. /label_this_number_square
  2100. {
  2101.     % takes lat_counter, lon_counter off stack
  2102.     % returns true/false
  2103.     % routine checks location of number_square
  2104.     % to see if it is on the outside (border) of a letter_square.
  2105.     % returns on/true - square will be labled with numbers
  2106.     % returns off/false - square will be left blank
  2107.     % if are in numbering-all-squares mode,
  2108.     % then evaluation short circuits to true
  2109.  
  2110.     % lat_counter & lon_counter defined in grid_locator_numbers_show
  2111.     {
  2112.     true
  2113.     label_all_number_squares_in_a_letter_square    % do it All!
  2114.     { exit } if
  2115.     lat_counter 0 eq
  2116.     { exit } if
  2117.     lat_counter 9 eq
  2118.     { exit } if
  2119.     lon_counter 0 eq
  2120.     { exit } if
  2121.     lon_counter 9 eq
  2122.     { exit } if
  2123.     not exit    % it's not true!
  2124.     } loop
  2125. }def
  2126.  
  2127. %--------------------------------------
  2128. /find_NSEW_limits
  2129. {
  2130.     % finds positions for the N,S,E,W limits
  2131.     % for drawing and labelling number squares
  2132.     % find values for globally defined variables
  2133.     %
  2134.     % northern_edge
  2135.     % southern_edge
  2136.     % eastern_edge
  2137.     % western_edge
  2138.     %
  2139.     % which are used by the routines
  2140.     % grid_locator_numbers_show, grid_locator_fine
  2141.  
  2142.  
  2143.     % find northern edge of the area which will have number labels
  2144.     % if QTH very close to (or exactly on) a letter square edge
  2145.     % then draw both the square above and below
  2146.  
  2147.     lat_QTH dup dup truncate sub abs
  2148.     very_small_distance lt
  2149.     {
  2150.         very_small_distance add
  2151.     } if % increase lat_QTH by very_small_distance
  2152.  
  2153.     % lat_QTH on top of stack
  2154.  
  2155.     10 div ceiling
  2156.     grid_locator_number_squares_northern_limit add 10 mul cvi
  2157.     /northern_edge exch def
  2158.  
  2159.     northern_edge 90 gt
  2160.     % can't label squares near poles
  2161.     % squares are too small and give divide by zero errors
  2162.     {
  2163.         /northern_edge 90 def
  2164.     } if
  2165.  
  2166.     % find southern edge of the area which will have number labels
  2167.     % if QTH very close to (or exactly on) a letter square edge
  2168.     % then draw both the square above and below
  2169.  
  2170.     lat_QTH dup dup truncate sub abs
  2171.     very_small_distance lt
  2172.     {
  2173.         very_small_distance sub
  2174.     } if    % decrease lat_QTH by very_small_distance
  2175.  
  2176.     %lat_QTH % on top of stack
  2177.     10 div floor
  2178.     grid_locator_number_squares_southern_limit sub 10 mul cvi
  2179.     /southern_edge exch def
  2180.  
  2181.     southern_edge 90 neg lt
  2182.     {
  2183.         /southern_edge 90 neg def
  2184.     } if
  2185.  
  2186.  
  2187.     % find eastern edge of the area which will have number labels
  2188.     % if QTH very close to (or exactly on) a letter square edge
  2189.     % then draw both the square to west and east
  2190.     lon_QTH dup dup truncate sub abs
  2191.     very_small_distance lt
  2192.     {
  2193.         very_small_distance add
  2194.     } if    % increase lon_QTH by very_small_distance
  2195.     %lon_QTH on top of stack
  2196.     20 div ceiling
  2197.     grid_locator_number_squares_eastern_limit add 20 mul cvi
  2198.     /eastern_edge exch def
  2199.  
  2200.     % find western edge of the area which will have number labels
  2201.     % if QTH very close to (or exactly on) a letter square edge
  2202.     % then draw both the square to west and east
  2203.     lon_QTH dup dup truncate sub abs
  2204.     very_small_distance lt
  2205.     {
  2206.         very_small_distance sub
  2207.     } if    % decrease lon_QTH by very_small_distance
  2208.  
  2209.     % lon_QTH on top of stack
  2210.     20 div floor
  2211.     grid_locator_number_squares_western_limit sub 20 mul cvi
  2212.     /western_edge exch def
  2213. } def
  2214.  
  2215. %--------------------------------------
  2216.  
  2217. /grid_locator_numbers
  2218. [
  2219.     (0) (1) (2) (3) (4) (5) (6) (7) (8) (9)
  2220. ] def
  2221.  
  2222. %--------------------------------------
  2223. /grid_num_str
  2224.     (locator numbers at lat,lon =           \b\b\b\b\b\b\b\b\b) def
  2225.  
  2226. /grid_locator_numbers_show
  2227. {
  2228.     (grid locator numbers: \n) print_notice
  2229.     /Helvetica-Bold findfont pop
  2230.     width_mh setlinewidth
  2231.     grid_locator_number_color setrgbcolor
  2232.     find_NSEW_limits
  2233.  
  2234.     southern_edge 1 northern_edge 1 sub    %each latitude
  2235.     {
  2236.         /mem_state save def
  2237.         dup /number_lat exch 0.5 add def
  2238.             % add to move into middle of square
  2239.         /lat_counter exch 90 add
  2240.             % make +ve no matter what, since
  2241.             % mod gives -ve answers
  2242.         10 mod def    % lat index
  2243.  
  2244.         western_edge 2 eastern_edge 2 sub        % each longitude
  2245.         {
  2246.             dup 1 add /number_lon exch def
  2247.  
  2248.             % send to error output, so we keep tabs on whats going on
  2249.             % add to move into middle of square
  2250.             send_notices verbose and
  2251.             {
  2252.                 grid_num_str print
  2253.                 number_lat 0.5 sub cvi grid_string cvs print
  2254.                 COMMA print
  2255.                 number_lon 1 sub grid_string cvs print CR print
  2256.                 flush
  2257.             } if
  2258.  
  2259.             /lon_counter exch 180 add
  2260.             % make +ve no matter what or
  2261.             % else mod will give -ve answers
  2262.             20 mod 2 idiv def % lon index
  2263.  
  2264.  
  2265.             label_this_number_square
  2266.             % if labelling are we in border
  2267.             % or do it all mode
  2268.             {
  2269.                 % I just fiddled slopes and negs and x1, y1's etc
  2270.                 % until the orientation was right on the screen
  2271.                 % - the math may not be right - JM
  2272.                 [ -1 1 ]
  2273.                 {
  2274.                     /posn exch def
  2275.                     gsave
  2276.                     % first letter, move left 0.4 degrees
  2277.                     number_lat number_lon 0.4 posn mul add
  2278.                     azimuthal_projection moveto
  2279.                     % find the local slope of the lon lines
  2280.                     % - stand letters on them
  2281.                     number_lat number_lon 0.4 posn mul add 0.1 add
  2282.                     azimuthal_projection
  2283.                     % x on top of stack, y next
  2284.                     /y1 exch def
  2285.                     /x1 exch def
  2286.                     number_lat number_lon 0.4 posn mul add 0.1 sub
  2287.                     azimuthal_projection
  2288.                     % x on top of stack, y next
  2289.                     /y2 exch def
  2290.                     /x2 exch def
  2291.  
  2292.                     % find how stretched out things are in the lon
  2293.                     % direction so we know how big to make letters
  2294.                     y1 y2 sub dup /lon_y exch def
  2295.                     % save x component of lon vector
  2296.                     dup mul            % and square it
  2297.                     x1 x2 sub dup /lon_x exch def
  2298.                     % save y component of lon vector
  2299.                     dup mul            % and square it
  2300.                     add sqrt /lon_len exch def    % length of lon vector
  2301.                                 % (for normalising)
  2302.  
  2303.                     % find the local slope of the lat lines
  2304.                     number_lat 0.4 sub 0.1 add number_lon
  2305.                     azimuthal_projection
  2306.                     % x on top of stack, y next
  2307.                     /y1 exch def /x1 exch def
  2308.                     number_lat 0.4 sub 0.1 sub number_lon
  2309.                     azimuthal_projection
  2310.                     % x on top of stack, y next
  2311.                     /y2 exch def /x2 exch def
  2312.  
  2313.                     % find how stretched out things
  2314.                     % are in the lat direction so
  2315.                     % we know how big to make letters
  2316.                     y1 y2 sub dup /lat_y exch def dup mul
  2317.                     x1 x2 sub dup /lat_x exch def dup mul
  2318.                     add sqrt /lat_len exch def
  2319.  
  2320.                     % near poles, due to limited precision of
  2321.                     % ghostscript, lon_len=0,
  2322.                     % need to trap 0 div error
  2323.                     lon_len very_small_distance lt
  2324.                     {
  2325.                         % don't even try to handle it
  2326.                         exit
  2327.                     }{
  2328.  
  2329.                         [
  2330.                         lon_x lon_len div lon_y lon_len div
  2331.                         lat_x lat_len div lat_y lat_len div
  2332.                         0            0
  2333.                         ] concat
  2334.  
  2335.                         /Helvetica-Bold findfont
  2336.                         grid_locator_number_font_scale
  2337.                         scalefont setfont
  2338.  
  2339.                         grid_locator_numbers
  2340.                         posn -1 eq
  2341.                             {
  2342.                                 lon_counter
  2343.                             }
  2344.                             {
  2345.                                 lat_counter
  2346.                             } ifelse get
  2347.                         % stringwidth, the setfont and the charpath routines
  2348.                         % are responsible for chewing up alot of VM.
  2349.                         dup stringwidth
  2350.  
  2351.                         % wx, wy on stack, adjust till looks about right
  2352.                         pop grid_locator_number_font_scale
  2353.                         3 div neg exch neg 2 div exch rmoveto
  2354.                         true charpath stroke
  2355.                     } ifelse % trap if near poles
  2356.                 grestore
  2357.                 } forall % 1st & 2nd numbers
  2358.             } if % label_this_number_square
  2359.         } for % sweep along this lon
  2360.         mem_state restore
  2361.     } for %each latitude
  2362.     (\n) print_notice
  2363. } def % grid_locator_numbers_show
  2364.  
  2365. %--------------------------------------
  2366.  
  2367. /grid_locator_letter_font_scale
  2368. {
  2369.     % this code replaces last years winner of the
  2370.     % obfuscated Postscript competition
  2371.     lat_len lon_len gt { lon_len }{ lat_len } ifelse 45 mul
  2372. } def
  2373.  
  2374. %--------------------------------------
  2375.  
  2376. /grid_locator_number_font_scale
  2377. {
  2378.     grid_locator_letter_font_scale 10 div
  2379. } def
  2380.  
  2381. %--------------------------------------
  2382. /grid_let_str
  2383.     (locator letters at lat,lon =           \b\b\b\b\b\b\b\b\b) def
  2384.  
  2385. /grid_locator_letters
  2386. [
  2387.     (A) (B) (C) (D) (E) (F) (G) (H) (I) (J) (K) (L) (M) (N) (O) (P) (Q) (R)
  2388. ] def
  2389.  
  2390. /grid_locator_letters_show
  2391. {
  2392.     mark
  2393.     (grid locator letters: \n) print_notice
  2394.     width_mh setlinewidth
  2395.     /Helvetica-Bold findfont pop    %load the font
  2396.     %
  2397.     % there is some wierd bug here that I haven't traced
  2398.     % the pair of numbers 110, 110 get left on the stack
  2399.     % when get to lat -45, lon 110
  2400.     % I don't know what it's about, as it doesn't happen at any other place
  2401.     % in this set of loops. You can see this bug by uncommenting the lone
  2402.         % pstack
  2403.     % command at the bottom of the -170 20 170 loop
  2404.     %
  2405.     % Since the bug seems benign, I've handled it by putting a mark on the stack
  2406.     % and then clearing to the mark on exiting from this routine
  2407.     % JM, Mar 95
  2408.  
  2409.  
  2410.     -85 10 +85            % each latitude
  2411.     {
  2412.         /mem_state save def
  2413.         dup /letter_lat exch def
  2414.  
  2415.         /lat_counter exch 85 add 10 div def        % lat index
  2416.  
  2417.         -170 20 170    %each longitude
  2418.         {
  2419.             dup /letter_lon exch def
  2420.             send_notices verbose and
  2421.             {
  2422.                 grid_let_str print
  2423.                 letter_lat grid_string cvs print COMMA print
  2424.                 letter_lon grid_string cvs print CR print
  2425.                 flush
  2426.             } if
  2427.  
  2428.             letter_lat letter_lon gc
  2429.             pop    % bearing, leaving dist on stack
  2430.                 % test if are near the antipodes
  2431.                 % only draw grid squares in which whole of square
  2432.                 % is inside the antipodes
  2433.                 % the other ones, which spill over onto the other
  2434.                 % side of the world aren't handled real well and
  2435.                 % have HUGE letters
  2436.  
  2437.             170 lt    % is it closer than 170 deg away?
  2438.             {
  2439.                 /lon_counter exch 170 add 20 div def    % lon index
  2440.  
  2441.                 [ -1 1 ]
  2442.                 {
  2443.                     /posn exch def
  2444.                     gsave    % first letter, move left 4 degrees
  2445.                         % second letter move right 4 degrees
  2446.                     letter_lat letter_lon 4 posn mul add
  2447.                     azimuthal_projection moveto
  2448.                         % I just fiddled slopes and negs and x1, y1's etc
  2449.                         % until the orientation was right on the screen
  2450.                         % - the math may not be right - JM
  2451.                         % find the local slope of the lon lines
  2452.                         %    - stand letters on them
  2453.                     letter_lat letter_lon 4 posn mul add 0.1 add
  2454.                     azimuthal_projection
  2455.                         % x on top of stack, y next
  2456.                     /y1 exch def
  2457.                     /x1 exch def
  2458.                     letter_lat letter_lon 4 posn mul add 0.1 sub
  2459.                     azimuthal_projection
  2460.                         % x on top of stack, y next
  2461.                     /y2 exch def
  2462.                     /x2 exch def
  2463.                         % find how stretched out things are in the lon
  2464.                         % direction so we know how big to make letters
  2465.                     y1 y2 sub dup /lon_y exch def
  2466.                         % save x component of lon vector
  2467.                     dup mul    % and square it
  2468.                     x1 x2 sub dup /lon_x exch def
  2469.                         % save y component of lon vector
  2470.                     dup mul    % and square it
  2471.                     add sqrt
  2472.                     /lon_len exch def
  2473.                         % length of lon vector (for normalising)
  2474.                         % find the local slope of the lat lines
  2475.                     letter_lat 0.1 add letter_lon 4 posn mul add
  2476.                     azimuthal_projection
  2477.                         % x on top of stack, y next
  2478.                     /y1 exch def
  2479.                     /x1 exch def
  2480.                     letter_lat 0.1 sub letter_lon 4 posn mul add
  2481.                     azimuthal_projection
  2482.                         % x on top of stack, y next
  2483.                     /y2 exch def
  2484.                     /x2 exch def
  2485.                         % find how stretched out things are in the
  2486.                         % lat direction so we know how big to
  2487.                         % make letters
  2488.                     y1 y2 sub dup /lat_y exch def
  2489.                     dup mul
  2490.                     x1 x2 sub dup /lat_x exch def
  2491.                     dup mul
  2492.                     add sqrt
  2493.                     /lat_len exch def
  2494.  
  2495.                     [
  2496.                     lon_x lon_len div lon_y lon_len div
  2497.                     lat_x lat_len div lat_y lat_len div
  2498.                     0            0
  2499.                     ] concat
  2500.                     /Helvetica-Bold findfont
  2501.                     grid_locator_letter_font_scale scalefont setfont
  2502.                     grid_locator_letter_color setrgbcolor
  2503.                     grid_locator_letters
  2504.                     posn -1 eq
  2505.                     { lon_counter }{ lat_counter } ifelse cvi get
  2506.                         % char on top of stack
  2507.                     dup stringwidth
  2508.                         % wx, wy on stack, adjust till looks about right
  2509.                     pop grid_locator_letter_font_scale 3 div neg
  2510.                     exch neg 2 div exch rmoveto true charpath
  2511.                     stroke
  2512.                     grestore
  2513.                 } forall % 1st and 2nd letters
  2514.             }if %170 lt
  2515.             %pstack    % uncomment this to see the numbers 110, 110 appear on the stack
  2516.         } for % sweep along this latitude
  2517.         mem_state restore
  2518.     } for % each latitude
  2519.     LF verbose_notice
  2520.     cleartomark
  2521. }def
  2522.  
  2523.  
  2524. %--------------------------------------
  2525.  
  2526. /LAT_FLAG true def
  2527. /LON_FLAG false def
  2528.  
  2529. /grid_lat_str
  2530.     (latitude line              =           \b\b\b\b\b\b\b\b\b) def
  2531.  
  2532. /grid_locator_lat
  2533. {
  2534.  
  2535.     %figure out spacing
  2536.     draw_alternate_lat_lon_spacing
  2537.     draw_letter_square_labels        not    and        % and they're off too
  2538.     draw_number_square_labels        not and        % and they're off too
  2539.     {
  2540.         alternate_lat_spacing /lat_spacing exch def
  2541.     }
  2542.     {
  2543.         /lat_spacing 10 def
  2544.     } ifelse
  2545.  
  2546.  
  2547.  
  2548.  
  2549.     -90 lat_spacing add lat_spacing +90 lat_spacing    sub            % each latitude
  2550.     {
  2551.         /start_lat exch def
  2552.         start_lat 0 eq
  2553.             {
  2554.                 width_mh grid_line_emphasis mul setlinewidth
  2555.             }
  2556.             {
  2557.                 width_mh setlinewidth
  2558.             } ifelse
  2559.         send_notices verbose and
  2560.         {
  2561.             grid_lat_str print
  2562.             start_lat grid_string cvs print CR print
  2563.             flush
  2564.         } if
  2565.  
  2566.         start_lat neg lat_QTH sub abs 0.1 lt
  2567.         {
  2568.             LAT_FLAG start_lat -179 lon_QTH add 179 lon_QTH add contour_draw
  2569.         }{
  2570.             LAT_FLAG start_lat -180 180 contour_draw
  2571.         } ifelse
  2572.     } for
  2573.     LF verbose_notice
  2574. }def
  2575.  
  2576. %--------------------------------------
  2577.  
  2578. /grid_lon_str
  2579.     (longitude line             =           \b\b\b\b\b\b\b\b\b) def
  2580.  
  2581. /grid_locator_lon
  2582. {
  2583.  
  2584.     %figure out spacing
  2585.     draw_alternate_lat_lon_spacing
  2586.     draw_letter_square_labels        not    and        % and they're off too
  2587.     draw_number_square_labels        not and        % and they're off too
  2588.     {
  2589.         alternate_lon_spacing /lon_spacing exch def
  2590.     }
  2591.     {
  2592.         /lon_spacing 20 def    %for grid_locators
  2593.     } ifelse
  2594.  
  2595.  
  2596.     -180 lon_spacing +180                %each longitude line
  2597.     {
  2598.         /start_lon exch def
  2599.         start_lon 0 eq
  2600.             {
  2601.                 width_mh grid_line_emphasis mul setlinewidth
  2602.             }
  2603.             {
  2604.                 width_mh setlinewidth
  2605.             } ifelse
  2606.  
  2607.         send_notices verbose and
  2608.         {
  2609.             grid_lon_str print
  2610.             start_lon grid_string cvs print CR print
  2611.             flush
  2612.         } if
  2613.  
  2614.         start_lon dup 0 lt { 180 }{ -180 } ifelse add lon_QTH sub abs 0.1 lt
  2615.         {
  2616.             LON_FLAG start_lon lat_QTH neg 1 add 89 contour_draw
  2617.             LON_FLAG start_lon -89 lat_QTH neg 1 sub contour_draw
  2618.         }{
  2619.             LON_FLAG start_lon -89 89 contour_draw
  2620.         } ifelse
  2621.     } for
  2622.     LF verbose_notice
  2623. } def
  2624.  
  2625. %--------------------------------------
  2626. /contour_draw
  2627. {
  2628.  
  2629.     /end_point    exch def
  2630.     /counter    exch def    % the initial point in the line
  2631.     /fixed_ord    exch def    % the fixed ordinate
  2632.     /lon_lat    exch def    % flag to tell us up or down!
  2633.  
  2634.  
  2635. %    After each point is transformed from mercator space to azimithal
  2636. %    space, its displacement from the previous point is checked (actually
  2637. %    the square of the displacement). If it is greater than 'max' amount
  2638. %    we halve our steps in mercator space. If it is less than 'min' amount
  2639. %    we double our steps.
  2640. %    This works, but is not a great algorythm. It is designed to handle
  2641. %    lines near the antipodes, which move very quickly in az projection
  2642. %    space for small changes in lat/lon space. However for QTHs very near
  2643. %    the poles, the latitude lines are tightly circular and this routine
  2644. %    will produce a lot of jaggies, unless max is kept small. Meanwhile the
  2645. %    longitude lines are very straight and are drawn in unneccessary detail.
  2646.  
  2647.     /incr 0.5 def        % initial step in mercator space
  2648.     /min 1.0 def        % the square of the minimum step in az space
  2649.     /max 4.0 def        % the square of the maximum step in az space
  2650.  
  2651.     newpath counter fixed_ord lon_lat { exch } if azimuthal_projection
  2652.     moveto
  2653.  
  2654.     {
  2655.         counter fixed_ord lon_lat { exch } if azimuthal_projection
  2656.  
  2657.         currentpoint 2 index sub dup mul    % square of distance is sum
  2658.         exch 3 index sub dup mul add    % of squares of x & y distance
  2659.         dup max gt incr incr_lim gt and
  2660.         {
  2661.             /incr incr 2.0 div def pop pop pop
  2662.             /counter counter incr sub def
  2663.         }{ % too much movement - halve step
  2664.             min lt
  2665.             {
  2666.                 /incr incr 2.0 mul def    % we move too little in az space
  2667.             } if                % we draw even if we are less
  2668.                             % than min distance
  2669.             lineto
  2670.             counter end_point ge { exit } if
  2671.             /counter incr counter add def
  2672.         } ifelse
  2673.     } loop
  2674.     %width_mh setlinewidth stroke
  2675.     % set linewidth in calling routines, so can make GMT, equator lines thicker
  2676.     stroke
  2677. } def
  2678.  
  2679. %--------------------------------------
  2680.  
  2681. /grid_locator_coarse
  2682. {
  2683.     (Letter grid squares: \n) print_notice
  2684.     newpath
  2685.     grid_locator_letter_color 1 1 3 { pop shade mul 3 1 roll } for setrgbcolor
  2686.     grid_locator_lat
  2687.     grid_locator_lon
  2688. } def
  2689.  
  2690. %--------------------------------------
  2691.  
  2692. /grid_fine_lat_str
  2693.     (latitude  line             =           \b\b\b\b\b\b\b\b\b) def
  2694.  
  2695. /grid_fine_lon_str
  2696.     (longitude line             =           \b\b\b\b\b\b\b\b\b) def
  2697.  
  2698. /grid_locator_fine
  2699. {
  2700.     gsave
  2701.     (\nNumber grid squares: \n) print_notice
  2702.  
  2703.     find_NSEW_limits % only do for limited number of squares
  2704.  
  2705.     grid_locator_number_color 1 1 3 { pop shade mul 3 1 roll } for
  2706.     setrgbcolor
  2707.     1 setlinejoin fine_gl_width setlinewidth
  2708.     number_square_edges_dashed {[.1 .25] 0 setdash} if
  2709.  
  2710.     southern_edge 1 northern_edge        % each latitude
  2711.     {
  2712.         /start_lat exch def
  2713.         send_notices verbose and
  2714.         {
  2715.             grid_fine_lat_str print
  2716.             start_lat grid_string cvs print CR print
  2717.             flush
  2718.         } if
  2719.  
  2720.         newpath
  2721.         start_lat western_edge
  2722.         azimuthal_projection
  2723.         moveto
  2724.         western_edge 1 eastern_edge
  2725.             % draw in 1 deg segments to get curved line
  2726.         {
  2727.             start_lat exch        % other point from do loop counter
  2728.             azimuthal_projection
  2729.             lineto
  2730.         } for            % sweep along this latitude
  2731.         stroke
  2732.     } for            %each latitude
  2733.     (\n) print_notice
  2734.     western_edge 2 eastern_edge    %each longitude line
  2735.     {
  2736.         /start_lon exch def
  2737.         send_notices verbose and
  2738.         {
  2739.             grid_fine_lon_str print
  2740.             start_lon grid_string cvs print CR print
  2741.             flush
  2742.         } if
  2743.  
  2744.         newpath
  2745.         southern_edge start_lon
  2746.         azimuthal_projection
  2747.         moveto
  2748.  
  2749.         southern_edge 1 northern_edge
  2750.         {
  2751.             start_lon azimuthal_projection
  2752.             lineto
  2753.         } for    % sweep along this longitude
  2754.         stroke
  2755.     } for    % each longitude
  2756.     LF verbose_notice
  2757.     grestore
  2758. } def
  2759.  
  2760.  
  2761. %--------------------------------------
  2762.  
  2763. /outer_border
  2764. {
  2765.     (Outer Border \n) print_notice
  2766.     gsave
  2767.     atom 2 mul setlinewidth
  2768.     outer_border_color setrgbcolor
  2769.     newpath
  2770.     0 0 180 0 360 arc closepath stroke
  2771.     0 0 180 atom 40 mul add 0 360 arc closepath stroke
  2772.  
  2773.     180 atom 40 mul add
  2774.  
  2775.         %compass_rose
  2776.         %Used to call compass_rose here, but color of outer_border is not passed.
  2777.         %Here is same routine with its own color
  2778.  
  2779.     newpath
  2780.     gsave
  2781.     /rad exch def
  2782.     atom 2 mul setlinewidth
  2783.     0 5 359
  2784.     {
  2785.         rad 0 moveto
  2786.         dup cvi 15 idiv exch 15.0 div sub 0 eq { 30 }{ 17 } ifelse
  2787.         atom mul neg 0 rlineto stroke
  2788.         5 rotate
  2789.     } for
  2790.     0 0 rad 0 360 arc closepath stroke
  2791.     grestore
  2792.  
  2793.     180 atom 50 mul add label_compass_directions
  2794.     grestore
  2795. } def
  2796.  
  2797. %--------------------------------------
  2798.  
  2799. /compass_rose
  2800. {
  2801.     newpath
  2802.     gsave
  2803.     /rad exch def % in degrees
  2804.     atom 2 mul setlinewidth
  2805.     compass_color setrgbcolor
  2806.     0 5 359
  2807.     {
  2808.         rad 0 moveto
  2809.         dup cvi 15 idiv exch 15.0 div sub 0 eq { 30 }{ 17 } ifelse
  2810.         atom mul neg 0 rlineto stroke
  2811.         5 rotate
  2812.     } for
  2813.     0 0 rad 0 360 arc closepath stroke
  2814.     grestore
  2815. } def
  2816.  
  2817. %--------------------------------------
  2818.  
  2819. /label_compass_directions
  2820. {
  2821.     gsave
  2822.     /rad exch def
  2823.     compass_label_color setrgbcolor
  2824.     /Helvetica findfont bearing_fontsize scalefont setfont
  2825.     360 compass_label_increment neg 1
  2826.     {
  2827.         0 rad moveto name cvs dup stringwidth pop 2 div neg
  2828.         bearing_fontsize 2 mul neg rmoveto show
  2829.         compass_label_increment rotate
  2830.     } for
  2831.     (Compass Directions\n) print_notice
  2832.     grestore
  2833. } def
  2834.  
  2835. %--------------------------------------
  2836.  
  2837. /draw_bearing_rose
  2838. {
  2839.     (\nCompass Circumference\n) print_notice
  2840.  
  2841.     % A few problems need to be handled here.
  2842.     % First the radius of the compass(es) needs to be determined.
  2843.     % Then the circumference is drawn
  2844.     % Then the spokes are drawn.
  2845.     % Then the labels need to be drawn on the spokes.
  2846.     % If the spokes are drawn after the labels, then some of the directions
  2847.     % eg "315" degrees will have a spoke drawn over the "1".
  2848.     % Since several compasses/spokes/label sets can be drawn here,
  2849.     % the largest compass is drawn first, then the spokes. After that
  2850.     % the spoke_drawing is turned off. Then subsequent compasses and
  2851.     % labels are drawn.
  2852.  
  2853.  
  2854.     % find the "ballpark" (1000. 100 or 10 kms)
  2855.     /Helvetica findfont bearing_fontsize scalefont setfont
  2856.  
  2857.     % see if QTH is off the map, and if so handle the compass drawing
  2858.     % differently
  2859.     lat_center lon_center gc /mbear exch def /mdist exch def
  2860.     mdist map_scale_deg sub deg2km 0 gt
  2861.     {
  2862.         % QTH is off the page (or nearly so)
  2863.         % We 'round' off the distance to the centre
  2864.         % order_of_mag from /setup_dimensions
  2865.  
  2866.         mdist deg2km order_of_mag div cvi order_of_mag mul /datum exch def
  2867.  
  2868.         % we find the compass rose that is the largest that will fit
  2869.         % on the page (in increments of the order of magnitude)
  2870.         9 -1 1
  2871.         {
  2872.             order_of_mag mul /limit exch def
  2873.             limit km2deg map_scale_deg .9 mul lt
  2874.             {
  2875.                 exit
  2876.             } if
  2877.         } for
  2878.         % draw this larger compass rose if it is within the world
  2879.         datum limit add dup km2deg dup 170 lt
  2880.         {
  2881.             /rad exch def %need value for rad in draw_spokes
  2882.             %rad = (rad 1 \n ) print_notice
  2883.             rad compass_rose
  2884.             draw_compass_spokes
  2885.                 {
  2886.                     draw_spokes
  2887.                     /draw_compass_spokes off def
  2888.                 } if
  2889.             rad label_compass_directions
  2890.             rad mbear km_show
  2891.         }{
  2892.             pop pop
  2893.         } ifelse
  2894.  
  2895.         % draw the compass rose if it is inside the globe (less than 180 deg) and
  2896.         % greater than 1/4 of the page.
  2897.         datum km2deg dup map_scale_deg 0.25 mul ge exch 170 lt and
  2898.         {
  2899.             datum dup km2deg %radius
  2900.             /rad exch def %need value for rad in draw_spokes
  2901.             %rad = (rad 2 \n ) print_notice
  2902.             rad compass_rose % these two routine need radius on the stack
  2903.             draw_compass_spokes
  2904.                 {
  2905.                     draw_spokes
  2906.                     /draw_compass_spokes off def
  2907.                 } if
  2908.             rad label_compass_directions
  2909.             rad mbear km_show
  2910.         } if
  2911.  
  2912.         % draw the size below the datum if it isn't smaller than 1/4 screen
  2913.         datum limit sub dup km2deg dup map_scale_deg 0.25 mul ge
  2914.         {
  2915.             /rad exch def %need value for rad in draw_spokes
  2916.             %rad = (rad 3 \n ) print_notice
  2917.             rad    compass_rose
  2918.             draw_compass_spokes
  2919.                 {
  2920.                     draw_spokes
  2921.                     /draw_compass_spokes off def
  2922.                 } if
  2923.             rad label_compass_directions
  2924.             rad mbear km_show
  2925.         }{
  2926.             pop pop
  2927.         } ifelse
  2928.     } if
  2929.  
  2930.     % draw a rose on the screen (largest that corresponds to a multiple
  2931.     % of 1, 2, or 5 times the order of magnitude
  2932.  
  2933.     [ 5 2 1 ]
  2934.     {
  2935.         dup order_of_mag mul map_scale_deg compass_coerce deg2km lt
  2936.         {
  2937.             exit
  2938.         }{
  2939.             pop
  2940.         } ifelse
  2941.     } forall
  2942.  
  2943.     order_of_mag mul dup km2deg dup 170 lt
  2944.     {
  2945.         /rad exch def %need value for rad in draw_spokes
  2946.          %rad = (rad 4 \n ) print_notice
  2947.         rad compass_rose
  2948.         draw_compass_spokes
  2949.             {
  2950.                 draw_spokes
  2951.                 /draw_compass_spokes off def
  2952.             } if
  2953.         rad label_compass_directions
  2954.         rad compass_label_color  1 1 3 { pop shade mul 3 1 roll } for setrgbcolor
  2955.         0 exch moveto cvi 10 string cvs dup stringwidth pop
  2956.         ( km) stringwidth pop add 2 div neg 0 rmoveto show ( km) show
  2957.     }{
  2958.         pop pop
  2959.     } ifelse
  2960. } def
  2961.  
  2962. %--------------------------------------
  2963. /draw_distance_circles
  2964. % around QTH
  2965. % on stack - radius of circle in km
  2966. {
  2967.     dup
  2968.     /rad_km exch def    % radius of circle in km
  2969.     km2deg /rad exch def    % radius of circle in degrees
  2970.     rad_km rad 0 km_show
  2971.  
  2972.     newpath
  2973.     gsave
  2974.     atom 2 mul setlinewidth
  2975.     compass_color setrgbcolor
  2976.     0 0 rad 0 360 arc closepath stroke
  2977.     grestore
  2978.  
  2979. }def
  2980. %--------------------------------------
  2981.  
  2982.  
  2983. /km_show
  2984. % print "XXXXkms"
  2985. % on stack: kilometers (real or int) <== first entry on stack (last off)
  2986. %        bearing (degrees)
  2987. %        distance (degrees)
  2988. {
  2989.     distance_bearing2xy moveto
  2990.     /Helvetica findfont bearing_fontsize scalefont setfont
  2991.     compass_label_color 1 1 3 { pop shade mul 3 1 roll } for
  2992.     setrgbcolor
  2993.     cvi name cvs dup stringwidth pop
  2994.     ( km) stringwidth pop add 2 div neg 0 rmoveto show ( km) show
  2995. } def
  2996.  
  2997. %-------------------------------------
  2998. /draw_spokes
  2999. {
  3000.     gsave
  3001.     %need extra space at end of string to clear previous line on screen
  3002.     (Compass Spokes            \n) print_notice
  3003.     % find the "ballpark" (1000. 100 or 10 kms)
  3004.     atom 2 mul setlinewidth
  3005.     compass_color setrgbcolor
  3006.     /min 0 def
  3007.     {
  3008.         /min min order_of_mag 10 div add def
  3009.         min map_scale_deg deg2km 6 div gt
  3010.         {
  3011.             exit
  3012.         } if
  3013.     } loop
  3014.  
  3015.     0 compass_spoke_interval 359  % change middle integer for difference spacings of spokes
  3016.     {
  3017.         30 mod 0 eq        % the first number in this line is the interval
  3018.                                     % between spokes that reach right to the center (=QTH)
  3019.         {
  3020.             0 0    % these lines start at center (ie QTH)
  3021.         }{
  3022.             0 min km2deg
  3023.                 %these lines start at dist=min away from QTH
  3024.         } ifelse
  3025.         moveto 0
  3026.  
  3027.         az_dict /rad known compass_spokes_to_antipodes not and
  3028.         {    rad    }    {    180    } ifelse
  3029.         lineto stroke
  3030.         % note rad is not defined unless have already executed compass_rose
  3031.         % incase this routine is not executed, rad is predefine at 180 (up top)
  3032.         newpath compass_spoke_interval rotate
  3033.     } for %compass_spoke_interval
  3034.     grestore
  3035. } def
  3036.  
  3037. %--------------------------------------
  3038. % Ghostscript has arccos.
  3039. % (Unfortunately Ghostscript arccos does not handle values <-1.0 and >1.0
  3040. % real well - the program will crash. Such numbers (eg 1.000001) can appear
  3041. % through rounding errors and are handled separately in the routine gc.)
  3042. %
  3043. % Standard postscript does not have a built in 'arccos', but using
  3044. % arctan', which it has, and some Pythagorean geometry we
  3045. % can synthesize it.    - M.K.
  3046. /Arccos
  3047. {
  3048.     % arccos(x) = arctan( sqrt( (1/x)**2 - 1) )
  3049.     /x exch def
  3050.     {
  3051.         x 1.0 gt
  3052.         { % x > 1, Error
  3053.             0.0 exit
  3054.         } if
  3055.         x -1.0 lt
  3056.         {  % x < 1, Error
  3057.             180.0 exit
  3058.         } if
  3059.  
  3060.         x 0.0 eq
  3061.         {
  3062.             90.0 exit
  3063.         } if
  3064.  
  3065.         1.0 x div dup mul 1 sub sqrt 1 atan
  3066.         x 0 lt
  3067.         {
  3068.             180 exch sub
  3069.         } if
  3070.         exit
  3071.     } loop
  3072. } bind def
  3073.  
  3074. %--------------------------------------
  3075.  
  3076.  
  3077. /gc
  3078. {
  3079.     % takes dest lat/lon on stack
  3080.     % pushes dist (in deg) bearing (deg) on stack
  3081.     %    Code adapted from
  3082.     % *    gc.c
  3083.     % *
  3084.     % *    Great Circle. This program is used to determine bearing
  3085.     % *    and range to a station given latitude and longitude data.
  3086.     % *
  3087.     % *    Ver 1.01 By S. R. Sampson, N5OWK
  3088.     % *    Public Domain (p) November 1989
  3089.     % *
  3090.     % *    Ref: Air Force Manual 51-40, "Air Navigation", 1 February 1987
  3091.     % *
  3092.  
  3093.     /DEST_Long exch def
  3094.     /DEST_Lat exch def
  3095.  
  3096.     %lat_QTH = (gc: lat_QTH \n) print_notice
  3097.     %lon_QTH = (gc: lon_QTH \n) print_notice
  3098.  
  3099.     /QTH_Long lon_QTH def
  3100.     /QTH_Lat lat_QTH def
  3101.  
  3102.     %/* Compute the Bearing and Range, From the Formula in Chapter 23 */
  3103.  
  3104.     DEST_Long QTH_Long sub /Delta_Long exch def
  3105.  
  3106.     QTH_Lat sin DEST_Lat sin mul
  3107.     QTH_Lat cos DEST_Lat cos mul Delta_Long cos mul
  3108.     add
  3109.  
  3110.     %Check for out of range numbers before running arccos
  3111.     dup 1.0 gt {pop 1.0}if
  3112.     dup -1.0 lt {pop -1.0}if
  3113.     arccos /dist exch def
  3114.  
  3115.     %if distance is very small (eg 0.0) then cannot determine bearing,
  3116.     %return bearing = 0
  3117.  
  3118.     very_small_distance dist gt
  3119.     {
  3120.         /bearing 0 def
  3121.     }{
  3122.         % if at the antipodes can't determine bearing either
  3123.         distance_to_antipodes dist lt
  3124.         {
  3125.             /bearing 0 def
  3126.         }{
  3127.             DEST_Lat sin QTH_Lat sin dist cos mul sub
  3128.             dist sin QTH_Lat cos mul div
  3129.             dup -1.0 lt { pop -1.0} if
  3130.             dup  1.0 gt { pop 1.0} if
  3131.             arccos
  3132.             /bearing exch def
  3133.  
  3134.             Delta_Long 180.0 gt
  3135.             {
  3136.                 Delta_Long 360 sub /Delta_Long exch def
  3137.             } if
  3138.  
  3139.             Delta_Long 0.0 lt
  3140.             {
  3141.                 Delta_Long -180 gt
  3142.                 {
  3143.                     360.0 bearing sub
  3144.                     /bearing exch def
  3145.                 } if
  3146.             } if
  3147.         } ifelse
  3148.     }ifelse
  3149.     dist bearing
  3150. }def %gc
  3151.  
  3152. %--------------------------------------
  3153.  
  3154. /distance_bearing2xy
  3155. {
  3156.     /bearing exch def
  3157.     /distance exch def    %is in degrees
  3158.  
  3159.     bearing sin neg distance mul
  3160.     % this is y
  3161.     neg
  3162.  
  3163.     bearing cos distance mul
  3164.     % this is x
  3165.  
  3166. }def
  3167.  
  3168. %--------------------------------------
  3169. /lat_lon2xy
  3170. %push lat on stack
  3171. %push lon on stack
  3172. %returns xy on stack ready for moveto
  3173. % x pops off first, then y
  3174. {
  3175.     gc distance_bearing2xy
  3176. }def
  3177. %--------------------------------------
  3178. % shorthand to extract elements from array
  3179. % eg 10 lon gets the longitude entry from the 10th element in the cood array
  3180.  
  3181. %/ini { coord 0 get exch get} def
  3182. %/lat { coord 1 get exch get} def
  3183. %/lon { coord 2 get exch get} def
  3184.  
  3185. /ini { coord exch get 0 get} def
  3186. /lat { coord exch get 1 get} def
  3187. /lon { coord exch get 2 get} def
  3188.  
  3189. /crunch_path
  3190. {
  3191.     %(crunch_path: start \n) print
  3192.     % digest line here!
  3193.  
  3194.     % determine line color, line width etc as a function of line type.
  3195.     % Also print, to stdout, the wdb index of the line as it is processed.
  3196.     % This output is handy for finding where a particular line segment
  3197.     % (wdb_path) is on the surface of the earth (that is if you are
  3198.     % viewing the output) as the lines are not labelled in the .wdb files.
  3199.     % As well the incrementing of numbers on the screen gives some assurance
  3200.     % that your computer is not frozen.
  3201.  
  3202.     % if this is the first (wdb) path (ie map segment) and we haven't
  3203.     % yet printed the grids, then do it now.
  3204.  
  3205.  
  3206.  
  3207.     0 ini
  3208.  
  3209.     %send_notices verbose and
  3210.     %{
  3211.     %    dup grid_string cvs print CR print
  3212.     %} if
  3213.  
  3214.     dup  /wdb_path exch def     % 4 digit number that labels each line (= path)
  3215.     1000 idiv 1 sub /feature_index exch def    % feature_index
  3216.  
  3217.  
  3218.     feature_index 0 ge
  3219.     {
  3220.         feature_color feature_index get exec setrgbcolor
  3221.         feature_width feature_index get atom mul setlinewidth
  3222.     } if
  3223.  
  3224.     newpath 0 lat 0 lon azimuthal_projection moveto
  3225.  
  3226.     i 1 gt
  3227.  
  3228.     % test if feature is turned on
  3229.     % we don't draw if any of these conditions are true
  3230.     % ie we don't draw if any of these features are turned off
  3231.  
  3232.     draw_coast_lines                not    feature_index 1    add    coast_line                eq    and
  3233.     draw_country_borders        not    feature_index 1    add country_border        eq    and    or
  3234.     draw_canadian_provinces    not    feature_index 1    add    Canadian_province    eq    and    or
  3235.     draw_us_states                    not feature_index 1    add US_state                     eq    and    or
  3236.     draw_islands                        not    feature_index 1    add island                        eq    and    or
  3237.     draw_lakes                            not    feature_index 1    add    lake                             eq    and    or
  3238.     draw_rivers                            not feature_index 1    add river                            eq    and    or
  3239.     draw_australian_states    not    feature_index 1    add    Australian_state    eq    and    or
  3240.         not    and
  3241.     {
  3242.         %(valid point \n) print
  3243.  
  3244.         1 1 i 1 sub
  3245.         {
  3246.             /ptr exch def
  3247.             ptr lat ptr lon
  3248.             azimuthal_projection lineto
  3249.         } for
  3250.  
  3251.         send_notices verbose and
  3252.         {
  3253.             %dup grid_string cvs print CR print
  3254.             feature_index 1 add
  3255.             dup coast_line eq        {(drawing coast line        ) print} if
  3256.             dup country_border eq    {(drawing country border    ) print} if
  3257.             dup Canadian_province eq {(drawing Canadian province ) print} if
  3258.             dup US_state eq          {(drawing US state          ) print} if
  3259.             dup island eq            {(drawing island            ) print} if
  3260.             dup lake eq              {(drawing lake              ) print} if
  3261.             dup river eq             {(drawing river             ) print} if
  3262.             dup Australian_state eq  {(drawing Australian state  ) print} if
  3263.             pop
  3264.             wdb_path grid_string cvs print CR print
  3265.             flush
  3266.         }if
  3267.  
  3268.         feature_index 0 ge
  3269.         {
  3270.             { % loop through all valid feature types
  3271.                 % (well those with positive indices anyhow)
  3272.  
  3273.                 % a special case
  3274.                 feature_index 1 add lake eq lake_fill and
  3275.                 {    % it's a lake and it's being filled
  3276.                     gsave    % save path of lake outline
  3277.                     % feature_color feature_index get exec setrgbcolor
  3278.                     fill
  3279.                     /big_lake_found false def    %initialise
  3280.                      big_lakes
  3281.                     {    % array of big_lakes on stack
  3282.                         wdb_path eq map_scale_deg 30 lt and
  3283.                         { % this wdb_path is one of the big_lakes
  3284.                             % and the map scale is small
  3285.                             /big_lake_found true def    %found a big_lake
  3286.                             grestore                     %recall path
  3287.                             lake_edge_color    setrgbcolor
  3288.                             %feature_width feature_index get atom mul setlinewidth
  3289.                             stroke
  3290.                             % no other big lake will have this wdb_path
  3291.                             % so don't bother checking further
  3292.                             exit % to forall
  3293.                         } if % it's a big lake, stroke the edge
  3294.                     } forall % big_lakes
  3295.                     big_lake_found not
  3296.                     {
  3297.                         %if this wasn't a big_lake have to do matching grestore
  3298.                         grestore
  3299.                     } if
  3300.  
  3301.                  exit    % to end of valid feature,
  3302.                             % we've filled and stroked this lake
  3303.                             % so bypass default feature handling at bottom of routine
  3304.                 } if % a lake and are "filling"
  3305.  
  3306.                 % another special case, islands in lakes
  3307.                 feature_index 1 add island eq
  3308.                 {
  3309.                     % it's an island. Is it an island in a lake?
  3310.                     island_in_lake    % array of numbers, which are islands in lakes
  3311.                     {
  3312.                         % array of islands in lakes is on stack
  3313.                         wdb_path eq
  3314.                         % test if path is an island in a lake
  3315.                         {
  3316.                             % the current wdb_path is an island in a lake
  3317.                             % if drawn on a lake filled with say blue,
  3318.                             % then the island will then have to be filled with white
  3319.                             gsave
  3320.                             white setrgbcolor % 0 setgray % fill with white
  3321.                             fill
  3322.                             grestore
  3323.                             % feature_width feature_index get atom mul setlinewidth
  3324.                             % stroke     % deleted - handled below in default
  3325.                             exit % there's only one, don't need to check other elements in array
  3326.                         } if % this wdb_path is an island in a lake
  3327.                     } forall % members of island_in_lakes
  3328.                     %exit % have handled this island, bypass default method of plotting
  3329.                     %commented out previous line or else islands WITHOUT lakes are not plotted
  3330.                 } if % island
  3331.  
  3332.                 %another special case of State borders
  3333.                 feature_index 1 add Canadian_province eq
  3334.                 feature_index 1 add US_state                    eq    or
  3335.                 feature_index 1 add Australian_state    eq    or
  3336.                 {    % it's a state border
  3337.                     state_borders_dashed
  3338.                     {
  3339.                         % sample 1-3- patterns (my favorite for states JM)
  3340.                         %[20 atom mul 20 atom mul 60 atom mul 20 atom mul ] 0 setdash    % big dashes
  3341.                         %[ 5 atom mul  5 atom mul 15 atom mul  5 atom mul ] 0 setdash    % small dashes
  3342.                          [10 atom mul 10 atom mul 30 atom mul 10 atom mul ] 0 setdash % just right dashes
  3343.                     } if
  3344.                     % feature_width feature_index get atom mul setlinewidth
  3345.                     stroke
  3346.                     exit % bypass default handling
  3347.                 } if % state border
  3348.  
  3349.                 % default handling of normal features here
  3350.                 stroke
  3351.                 exit
  3352.             } loop % all types of features
  3353.         } if % valid feature (index ge 0)
  3354.     } if % line belongs to a feature to be drawn
  3355. [] 0 setdash % turn off dashes, just to be safe
  3356. az_dict /line_cnt line_cnt i add put
  3357. } def
  3358.  
  3359. %--------------------------------------
  3360.  
  3361.  
  3362. /azimuthal_projection
  3363. {
  3364.     gc distance_bearing2xy
  3365. } def
  3366.  
  3367. %--------------------------------------
  3368. /coord 2024 array def
  3369. /first_time true def
  3370. /Error_Flag -500 def    % none of the entries should be this
  3371. /i 0 def
  3372.  
  3373. /extract_coord_1
  3374. {
  3375.     % get first item, check that it is indeed an integer.
  3376.     % If first item is greater than 1000 then crunch_path. We can use 'i' to
  3377.     % indicate the number of entries in the arrays. After we return from
  3378.     % crunch_path we reset i.
  3379.     % If the token differs from what we expect, we indicate with an illegal
  3380.     % number
  3381.     /entry [ Error_Flag dup dup ] def
  3382.     token
  3383.     {
  3384.         dup type /integertype eq
  3385.         {
  3386.             dup 1000 ge first_time not and
  3387.             {
  3388.                 dup 0 ini ne
  3389.                 {
  3390.                     crunch_path  /i 0 def
  3391.                 }{
  3392.                     1000 mod
  3393.                 } ifelse
  3394.             } if
  3395.  
  3396.             entry 0  3 -1 roll  put
  3397.         }{
  3398.             pop
  3399.         } ifelse    % we expect an int first!
  3400.  
  3401.         token
  3402.         {
  3403.             dup type /realtype eq
  3404.             {
  3405.                 entry 1  3 -1 roll  put
  3406.             }{
  3407.                 pop    % we expect a real second!
  3408.             } ifelse
  3409.  
  3410.             token
  3411.             {
  3412.                 dup type /realtype eq
  3413.                 {
  3414.                     entry 2  3 -1 roll  put
  3415.                 }{
  3416.                     pop
  3417.                 } ifelse    % we expect a real second!
  3418.             } if
  3419.         } if
  3420.     } if
  3421.  
  3422.     clear
  3423.  
  3424.     coord i entry put
  3425.  
  3426.     % To avoid a limitcheck error,
  3427.     % we limit the path complexity to less than 1500 points.
  3428.     % n.b. this 1500 point limit includes all paths
  3429.     % (including current clippath)
  3430.     i 1450 ge
  3431.     {
  3432.         crunch_path /i 0 def
  3433.         % ensure we restart at the previous point
  3434.         entry 0 0 ini put coord 0 entry put
  3435.     }if
  3436.  
  3437.     /i i 1 add def
  3438.     /first_time false def
  3439.  
  3440. } def
  3441.  
  3442.  
  3443. %--------------------------------------
  3444. /coord 2024 array def
  3445. /first_time true def
  3446. /Error_Flag -500 def    % none of the entries should be this
  3447. /i 0 def
  3448.  
  3449. %/coord_size 1500 def
  3450. %/coord [ 0 1 2 { pop coord_size array } for ] def
  3451. %/first_time true def
  3452. %/Error_Flag -500 def    % none of the entries should be this
  3453. %/i 0 def
  3454.  
  3455. %%initialise
  3456. %/entry_id  0 def
  3457. %/entry_lat 0 def
  3458. %/entry_lon 0 def
  3459.  
  3460. /extract_coord
  3461. {
  3462.     % get first item, it should be a 4 digit wdb descriptor (type integer).
  3463.     % check that first item is indeed an integer.
  3464.     % If it is greater than 1000 then crunch_path.
  3465.     % We can use 'i' to indicate the number of entries in the arrays.
  3466.     % After we return from crunch_path we reset i.
  3467.     % If the token differs from what we expect, we indicate with an illegal
  3468.     % number
  3469.  
  3470.     %/entry_id  Error_Flag def
  3471.     %/entry_lat Error_Flag def
  3472.     %/entry_lon Error_Flag def
  3473.  
  3474.     /entry [ Error_Flag dup dup ] def
  3475.     token
  3476.     {
  3477.         dup type /integertype eq
  3478.         {
  3479.             dup 1000 ge first_time not and
  3480.             {
  3481.                 % get here if find wdb path descriptor (eg 1001)
  3482.                 % and are not here for the first time (ie have extracted previous coords)
  3483.                 % ie we are starting a 2nd or 3rd or nth wdb path
  3484.                 dup 0 ini ne { crunch_path /i 0 def    }{ 1000 mod    } ifelse
  3485.             } if
  3486.  
  3487.             %/entry_id exch def
  3488.             entry 0 3 -1 roll put
  3489.         }{
  3490.             pop % chuck the number
  3491.         } ifelse    % we expect the first number in a path to be a 4 digit int
  3492.  
  3493.         token
  3494.         {
  3495.             dup type /realtype eq
  3496.             {
  3497.                 %entry_lat exch def
  3498.                 entry 1 3 -1 roll put
  3499.             }{
  3500.                 pop    % we expect a real second!
  3501.             } ifelse
  3502.  
  3503.             token
  3504.             {
  3505.                 dup type /realtype eq
  3506.                 {
  3507.                     %/entry_lon exch def
  3508.                     entry 2 3 -1 roll put
  3509.                 }{
  3510.                     pop
  3511.                 } ifelse    % we expect a real third!
  3512.             } if
  3513.         } if
  3514.     } if
  3515.  
  3516.     clear
  3517.  
  3518.     %coord 0 get i entry_id     put
  3519.     %coord 1 get i entry_lat put
  3520.     %coord 2 get i entry_lon put
  3521.     coord i entry put
  3522.  
  3523.     % To avoid a limitcheck error,
  3524.     % we limit the path complexity to less than 1500 points.
  3525.     % n.b. this 1500 point limit includes all paths
  3526.     % (including current clippath)
  3527.     i 1450 ge
  3528.     {
  3529.         crunch_path
  3530.         /i 0 def    % reset i
  3531.         % ensure we restart at the previous point
  3532.         %/entry_id 0 ini def
  3533.         entry 0 0 ini put coord 0 entry put
  3534.  
  3535.         %coord 0 get 0 entry_id     put
  3536.         %coord 1 get 0 entry_lat put
  3537.         %coord 2 get 0 entry_lon put
  3538.  
  3539.     }if
  3540.  
  3541.     /i i 1 add def
  3542.     /first_time false def
  3543.  
  3544. } def
  3545.  
  3546.  
  3547. %--------------------------------------
  3548.  
  3549. %
  3550. % If we are using ghostscript or Display PS
  3551. % we can locate the script with an argument
  3552. % otherwise the script follows the programme as 'stdin'
  3553. %
  3554.  
  3555. /argno 0 def
  3556. /next_file
  3557. {
  3558.     userdict /ARGUMENTS known
  3559.     {
  3560.         userdict /ARGUMENTS get length 0 ne
  3561.     }{false} ifelse
  3562.     {
  3563.         % we have arguments
  3564.         {
  3565.             % loop until we have a good argument (or run out)
  3566.             userdict /ARGUMENTS get dup length
  3567.             argno le
  3568.             {    % check that we have any more arguments
  3569.                 pop false exit
  3570.             }{
  3571.                 argno get
  3572.                 /argno argno 1 add def
  3573.                 % If we know about ARGUMENTS (eg in gs),
  3574.                 % and we have arguments, we use the first one
  3575.                 % as a file name and attempt to open it
  3576.                     dup dup status
  3577.                 {
  3578.                     4 { pop } repeat
  3579.                     /data_file exch (r) file def
  3580.                     (Processing file ) print_notice print_notice
  3581.                     % write blank to obliterate data from previous line
  3582.                     (              \n) print_notice
  3583.                     true exit
  3584.                 }{
  3585.                     print  ( is not a valid filename. Cannot open. \n)
  3586.                     print flush
  3587.                     pop
  3588.                     } ifelse
  3589.             } ifelse
  3590.         } loop
  3591.     }{
  3592.         az_dict /data_file known
  3593.         {
  3594.             false    % if we've been here before then it's the end
  3595.         }{
  3596.             (\naz_proj.ps Attention: \n) print_notice
  3597.             (No command line arguments for map data found \n) print_notice
  3598.             (az_proj is looking for input on stdin.\n) print_notice
  3599.             (\n) print_notice
  3600.             (The input it wants is any (or no) map data, followed by an OEF \n) print_notice
  3601.             (\n) print_notice
  3602.             (Stdin can be a concatenated file fed with the command \n) print_notice
  3603.             (C:gs>type na_comb.ps | gs - \n) print_notice
  3604.             (If you've sent such a file, it will be being drawn as you read this. \n) print_notice
  3605.             (\n) print_notice
  3606.             (Stdin will be the terminal (the keyboard) if map data files, \n) print_notice
  3607.             (but controld.ps was not given as an argument to gs.\n) print_notice
  3608.             (In this case you can (if you really want to) send your own data \n) print_notice
  3609.             (lines to gs by hand, and when you've finished looking at the map, \n) print_notice
  3610.             (you can exit by entering EOF on the keyboard. \n) print_notice
  3611.             (\n) print_notice
  3612.             (Note: EOF depends on your operating system \n) print_notice
  3613.             (                     Unix   ctrl-D         \n) print_notice
  3614.             (                     VMS    ctrl-C         \n) print_notice
  3615.             (                     MSDOS  ctrl-Z, cr,    \n) print_notice flush
  3616.             /data_file (%stdin) (r) file def
  3617.             true
  3618.         } ifelse
  3619.     } ifelse
  3620. } def
  3621.  
  3622. %--------------------------------------
  3623. /grid_to_lat_lon
  3624. % 6 or 4 char grid locator, eg FM18rx, FM19 is on stack
  3625. % lat and lon are given lat/lon for center of square
  3626. {
  3627.  
  3628.     %(grid_to_lat_lon \n) print_notice
  3629.     %pstack
  3630.     /bad_loc false def
  3631.     /lat -90.0 def
  3632.     /lon -180.0 def
  3633.  
  3634.     dup
  3635.     length /loc_len exch def
  3636.  
  3637. % If we have more than 2 digits in the grid locator, then proceed
  3638.  
  3639.     loc_len 2 ge
  3640.         {
  3641.             %beacon_fields 2 get    % get grid_locator - old code
  3642.             % this is the grid locator, now passed on stack
  3643.             %(loc_len) loc_len pstack pop pop
  3644.  
  3645.             0 1 loc_len 1 sub
  3646.             {
  3647.  
  3648.                 /i exch def
  3649.                 dup i get % get the next digit
  3650.                 {
  3651.                     i 0 eq % first is a letter longitude
  3652.                     {
  3653.                         32 or 97 sub    % convert to lower case & make 0 to 18
  3654.                         dup 18 ge    % only 18 letters are allowed
  3655.                         {
  3656.                             /bad_loc true def
  3657.                             pop exit
  3658.                         } if
  3659.                         20 mul /lon exch lon add def
  3660.                         loc_len 2 eq    % if only 2 digits in GL string
  3661.                         {
  3662.                             % centre the beacon in Grid
  3663.                             /lon lon 10 add def
  3664.                         } if
  3665.                         exit
  3666.                     } if
  3667.  
  3668.                     i 1 eq    % 2nd letter, latitude
  3669.                     {
  3670.  
  3671.                         32 or 97 sub    % convert to lower case & make 0 to 18
  3672.                         dup 18 ge    % only 18 allowed
  3673.                         {
  3674.                             /bad_loc true def
  3675.                             pop exit
  3676.                         } if
  3677.                         10 mul /lat exch lat add  def
  3678.                         loc_len 2 eq    % center in GS if only 2 letters given
  3679.                         {
  3680.                             /lat lat 5 add def
  3681.                         } if
  3682.                         exit
  3683.                     } if
  3684.  
  3685.                     i 2 eq            % number longitude GS
  3686.                     {
  3687.                 %(got here 3 \n) print
  3688.  
  3689.                         48 sub        % make 0-9
  3690.                         dup 10 ge    % only 0 to 9 allowed
  3691.                         {
  3692.                             /bad_loc true def
  3693.                             pop exit
  3694.                         } if
  3695.                         2 mul /lon exch lon add def
  3696.                         loc_len 4 eq
  3697.                         {
  3698.                             /lon lon 1 add def
  3699.                         } if
  3700.                         exit
  3701.                     } if
  3702.  
  3703.                     i 3 eq
  3704.                     {
  3705.                 %(got here 4 \n) print
  3706.  
  3707.                         48 sub
  3708.                         dup 10 ge
  3709.                         {
  3710.                             /bad_loc true def
  3711.                             pop exit
  3712.                         } if
  3713.                         /lat exch lat add def
  3714.                         loc_len 4 eq
  3715.                         {
  3716.                             /lat lat 0.5 add def
  3717.                         } if
  3718.                         exit
  3719.                     } if
  3720.  
  3721.                     i 4 eq
  3722.                     {
  3723.                         32 or 97 sub    % convert to lower case & make 0 to 18
  3724.                         dup 24 ge
  3725.                         {
  3726.                             /bad_loc true def
  3727.                             pop exit
  3728.                         } if
  3729.                         5 60 div mul /lon exch lon add def
  3730.                         exit
  3731.                     } if
  3732.  
  3733.                     i 5 eq
  3734.                     {
  3735.                         32 or 97 sub    % convert to lower case & make 0 to 18
  3736.                         dup 24 ge            {
  3737.                         /bad_loc true def
  3738.                         pop exit
  3739.                     } if
  3740.                     2.5 60 div mul /lat exch lat add def
  3741.                     exit
  3742.                 } if
  3743.             } loop
  3744.         } for pop
  3745.     }{
  3746.         /bad_loc false def
  3747.     } ifelse
  3748. } def %grid_to_lat_lon
  3749.  
  3750. %--------------------------------------
  3751. %Instruction to execute to specially label a beacon
  3752. /beacon_special_1
  3753.     {
  3754.     %draw cross hairs around beacon, might be good for a B/W printer
  3755.     beacon_color setrgbcolor
  3756.     5 atom mul setlinewidth
  3757.     newpath  25 atom mul  25 atom mul moveto  25 atom mul  25 atom mul rlineto stroke
  3758.     newpath -25 atom mul -25 atom mul moveto -25 atom mul -25 atom mul rlineto stroke
  3759.     newpath -25 atom mul  25 atom mul moveto -25 atom mul  25 atom mul rlineto stroke
  3760.     newpath  25 atom mul -25 atom mul moveto  25 atom mul -25 atom mul rlineto stroke
  3761.     } def
  3762. /beacon_special_2
  3763.     {
  3764.     % make beacon red
  3765.     %/beacon_color {red} def
  3766.     beacon_color setrgbcolor
  3767.     } def
  3768. %/beacon_special {beacon_special_2} def    % now in az_ini.ps
  3769.  
  3770. % defaults
  3771. /mark_beacon {} def
  3772. /beacon_color /black cvx def
  3773.  
  3774.  
  3775. %--------------------------------------
  3776.  
  3777.  
  3778. /beacon_strings      [ 10 string 10 string 10 string ] def
  3779.  
  3780. /beacon_fields
  3781. [
  3782.     ()        % frequency in MHz (as a string)
  3783.     ()        % callsign
  3784.     ()        % grid locator (4 or 6 digit)
  3785.     20.0         % power
  3786.     30.0        % direction
  3787.     0
  3788. ] def
  3789.  
  3790.  
  3791. /extract_beacon
  3792. {
  3793. % defaults in case we don't find them in data
  3794.     beacon_fields 3 1.0 put         % power W
  3795.     beacon_fields 4 -1 put           % beam_heading, -1 => omni, 60=> 60deg true
  3796.     beacon_fields 5 0 put                % write label on top of symbol (1 = below)
  3797.  
  3798. % The fields in the beacon text are
  3799. %    beacon:144.020  NV3Z  FM18rx  15  90  1
  3800. % beacon:        <-- indicates a beacon line
  3801. % 144.020        <-- frequency
  3802. % NV3Z            <-- call sign  (n.b. do not use '/' in call or parser will freak out)
  3803. % FM18rx        <-- Grid locator. If only 2 or 4 digits supplied, the beacon is
  3804. %                                placed in the middle of the grid
  3805. % 15                <-- Power of beacon. Different symbols for  < 5W, < 50W, > 50W
  3806. % 90                <-- direction of beacon. If not supplied, or 360 given, omni assumed
  3807. % 1                    <-- label under symbol; 0 or no value - printed on top.
  3808.     {
  3809.     0 1 2
  3810.         {
  3811.         /i exch def
  3812.         token        % get first two strings
  3813.             {            % n.b. this is intolerant of "/" in string
  3814.             beacon_strings i get cvs beacon_fields i 3 -1 roll put
  3815.             }
  3816.             {
  3817.             exit
  3818.             } ifelse
  3819.         } for
  3820.  
  3821.     3 1 5
  3822.         {
  3823.         /i exch def
  3824.         token
  3825.             {        % power and direction are reals
  3826.             dup type /realtype eq 1 index type /integertype eq or
  3827.                 {
  3828.                 cvr beacon_fields i 3 -1 roll put
  3829.                 }
  3830.                 {
  3831.                 pop        % ignore if string
  3832.                 } ifelse
  3833.             }
  3834.             {
  3835.             exit
  3836.             } ifelse
  3837.         } for
  3838.     exit
  3839.     } loop
  3840.  
  3841. % Only print beacon if we have at least a location
  3842. %i 2 ge beacons_on and
  3843.     i 2 ge
  3844.         {
  3845.         Print_beacon
  3846.         } if
  3847. } def
  3848.  
  3849. %--------------------------------------
  3850. /correct_azimuth
  3851. %requires globals: beam_heading, lat, lon
  3852. {
  3853. % Have to fiddle with beam_heading, since while at QTH, Nth is up,
  3854. % on any other part of the map, Nth is not up (see CAVEAT in bea_w3ep.dat).
  3855. %
  3856. %    beam_heading = ( beam_heading \n) print_notice
  3857. %    lat = lon = (lat lon \n) print_notice
  3858. % beacon is at lat/lon.
  3859. % Find the location of a test point a small distance away (say 1 deg)
  3860. % from the beacon on a bearing of "beam_heading".
  3861.     lon beam_heading sin add /lon_test exch def
  3862.     lat beam_heading cos add /lat_test exch def
  3863. %    lat_test = lon_test = (lat_test lon_test \n) print_notice
  3864. % Find location of test point in x,y space
  3865.     lat_test lon_test lat_lon2xy /x_test exch def /y_test exch def
  3866. %    x_test = y_test = (x_test y_test \n) print_notice
  3867. % do same for beacon
  3868.     lat lon lat_lon2xy /x_beacon exch def /y_beacon exch def
  3869. %    x_beacon = y_beacon = (x_beacon y_beacon \n) print_notice
  3870. % find bearing on page (xy space) to test point from beacon
  3871.     y_test y_beacon sub x_test x_beacon sub atan /test_beam_heading exch def
  3872. %    test_beam_heading = (test_beam_heading \n) print_notice
  3873.     test_beam_heading /beam_heading exch def
  3874.     beam_heading 360 gt {beam_heading 360 sub /beam_heading exch def} if
  3875.     beam_heading 0 lt {beam_heading 360 add /beam_heading exch def} if
  3876. %    beam_heading = (beam_heading \n) print_notice
  3877.  
  3878. } def % correct_azimuth
  3879. %--------------------------------------
  3880.  
  3881. /Print_beacon
  3882. {
  3883.     /bad_loc false def
  3884.  
  3885.     /lat -90.0 def
  3886.     /lon -180.0 def
  3887.     /beacon_symbol_size atom 10 mul  def
  3888.     beacon_color setrgbcolor
  3889.  
  3890.     /loc_len beacon_fields 2 get length def
  3891.  
  3892.     beacon_fields 2 get
  3893.     %(test) pstack pop
  3894.     grid_to_lat_lon
  3895.  
  3896.     bad_loc not false
  3897.     beacons_plotted
  3898.         {
  3899.         beacon_fields 0 get cvi eq { not } if
  3900.         } forall and
  3901.  
  3902.     {
  3903.     /beam_heading beacon_fields 4 get def
  3904.  
  3905.     %(\n :) print_notice
  3906.     %beam_heading = (beam_heading, \n) print_notice
  3907.  
  3908.     beam_heading -1 eq
  3909.         {
  3910.         /beam_half_width 179.999 def
  3911.         /beam_heading 360 exch def
  3912.         }
  3913.         {
  3914.         % assume a 70deg beam width
  3915.         /beam_half_width 35 def
  3916.         } ifelse
  3917.  
  3918.     correct_azimuth
  3919.  
  3920.     /pwr beacon_fields 3 get dup
  3921.     0.0 le { pop 0 }{ 2 mul log cvi } ifelse  def
  3922.  
  3923.     gsave
  3924.         3 atom mul setlinewidth
  3925.         %0 setgray
  3926.         lat lon lat_lon2xy translate
  3927.         gsave
  3928.             mark_beacon
  3929.         grestore
  3930.         gsave
  3931.  
  3932.             % old code
  3933.             beam_half_width 35 ne { /beacon_symbol_size beacon_symbol_size 1.5 div def } if
  3934.             450 beam_heading sub rotate newpath
  3935.             % new code
  3936.             %beam_heading -1 eq { /beacon_symbol_size beacon_symbol_size 1.5 div def } if
  3937.             %90 rotate newpath % N for compass is -90 in cartesian
  3938.             0 0 beacon_symbol_size 0 360 arc
  3939.             gsave
  3940.                 %1.0 setgray
  3941.                  6 atom mul setlinewidth stroke
  3942.             grestore stroke
  3943.  
  3944.             beam_half_width 35 eq
  3945.                 {
  3946.                 0 0 beacon_symbol_size 315 45 arc
  3947.                 0 0 beacon_symbol_size 3 div 65 295 arcn closepath ffill
  3948.                 }
  3949.                 {
  3950.                 0 0 beacon_symbol_size 360 beam_half_width sub beam_half_width arc
  3951.                 0 0 beacon_symbol_size 3 div beam_half_width 360 beam_half_width sub arcn closepath ffill
  3952.                 } ifelse
  3953.  
  3954.             0 0 beacon_symbol_size 0 360 arc stroke
  3955.  
  3956.             pwr 0 gt
  3957.                 {
  3958.                 0 0 beacon_symbol_size 7 mul 3 div 360 beam_half_width sub beam_half_width arc
  3959.                 0 0 beacon_symbol_size 5 mul 3 div beam_half_width 360 beam_half_width sub arcn
  3960.                 closepath ffill
  3961.  
  3962.                 pwr 1 gt
  3963.                     {
  3964.                     0 0 beacon_symbol_size 12 mul 3 div 360 beam_half_width sub beam_half_width arc
  3965.                     0 0 beacon_symbol_size 10 mul 3 div beam_half_width 360 beam_half_width sub arcn
  3966.                     closepath ffill
  3967.                     } if
  3968.                 } if
  3969.         grestore
  3970.         beacon_font findfont beacon_font_size scalefont setfont
  3971.         beacon_color setrgbcolor
  3972.         beacon_fields 5 get  0 eq
  3973.             {
  3974.             0 pwr 1 add 4 mul 1 add 3 div beacon_symbol_size mul moveto
  3975.             }
  3976.             {
  3977.             0 pwr 1 add 4 mul 1 add 3 div beacon_symbol_size mul
  3978.             beacon_font_size add neg moveto
  3979.             } ifelse
  3980.         currentpoint
  3981.         beacon_fields 0 get dup stringwidth pop 2 div neg 0 rmoveto halo
  3982.         moveto 0 beacon_font_size
  3983.         beacon_fields 5 get 0 ne { neg } if rmoveto
  3984.         beacon_fields 1 get dup stringwidth pop 2 div neg 0 rmoveto halo
  3985.     grestore
  3986.     }
  3987.     {
  3988.     } ifelse
  3989. } def
  3990.  
  3991. %--------------------------------------
  3992. % this was originally copied from beacon_special
  3993.  
  3994. %Instruction to execute to specially label a repeater
  3995. /repeater_special_1
  3996.     {
  3997.     %draw cross hairs around repeater, might be good for a B/W printer
  3998.     repeater_color setrgbcolor
  3999.     5 atom mul setlinewidth
  4000.     newpath  25 atom mul  25 atom mul moveto  25 atom mul  25 atom mul rlineto stroke
  4001.     newpath -25 atom mul -25 atom mul moveto -25 atom mul -25 atom mul rlineto stroke
  4002.     newpath -25 atom mul  25 atom mul moveto -25 atom mul  25 atom mul rlineto stroke
  4003.     newpath  25 atom mul -25 atom mul moveto  25 atom mul -25 atom mul rlineto stroke
  4004.     } def
  4005. /repeater_special_2
  4006.     {
  4007.     % make repeater red
  4008.     %/repeater_color {red} def
  4009.     repeater_color setrgbcolor
  4010.     } def
  4011. %/repeater_special {repeater_special_2} def    % now in az_ini.ps
  4012.  
  4013. % defaults
  4014. /mark_repeater {} def
  4015. /repeater_color /black cvx def
  4016.  
  4017.  
  4018.  
  4019.  
  4020. %--------------------------------------
  4021. % this was originally copied from extract_beacon
  4022. /repeater_strings      [ 10 string 10 string 10 string ] def
  4023.  
  4024. /repeater_fields
  4025. [
  4026.     ()        % frequency in MHz with a trailing +/- for offset (string)
  4027.     ()        % callsign
  4028.     ()        % grid locator (4 or 6 digit)
  4029.     20.0         % power
  4030.     30.0        % direction
  4031.     0
  4032. ] def
  4033.  
  4034.  
  4035. /extract_repeater
  4036. {
  4037.     repeater_fields 3 1.0 put         % defaults in case we don't
  4038.     repeater_fields 4 -1 put   % find them in data
  4039.     repeater_fields 5 0 put                %   write label on top of symbol
  4040.  
  4041. % The fields in the repeater text are
  4042. %    repeater:147.21+  NA3T  FM119gh 15  90  1
  4043. % repeater:    <-- indicates a repeater line
  4044. % 147.21+        <-- frequency, with + (or -) offset
  4045. % NA3T            <-- call sign  (n.b. do not use '/' in call or parser will freak out)
  4046. % FM19gh        <-- Grid locator. If only 2 or 4 digits supplied, the repeater is
  4047. %                                placed in the middle of the grid
  4048. % 15                <-- Power of repeater. Different symbols for  < 5W, < 50W, > 50W
  4049. % 90                <-- direction of repeater. If not supplied, or 360 given, omni assumed
  4050. % 1                    <-- label under symbol; 0 or no value - printed on top.
  4051.     {
  4052.     0 1 2
  4053.         {
  4054.         /i exch def
  4055.         token        % get first two strings
  4056.             {            % n.b. this is intolerant of "/" in string
  4057.             repeater_strings i get cvs repeater_fields i 3 -1 roll put
  4058.             }
  4059.             {
  4060.             exit
  4061.             } ifelse
  4062.         } for
  4063.  
  4064.     3 1 5
  4065.         {
  4066.         /i exch def
  4067.         token
  4068.             {        % power and direction are reals
  4069.             dup type /realtype eq 1 index type /integertype eq or
  4070.                 {
  4071.                 cvr repeater_fields i 3 -1 roll put
  4072.                 }
  4073.                 {
  4074.                 pop        % ignore if string
  4075.                 } ifelse
  4076.             }
  4077.             {
  4078.             exit
  4079.             } ifelse
  4080.         } for
  4081.     exit
  4082.     } loop
  4083.  
  4084. % Only print repeater if we have at least a location
  4085. %i 2 ge repeaters_on and
  4086.     i 2 ge
  4087.         {
  4088.         Print_repeater
  4089.         } if
  4090. } def
  4091.  
  4092.  
  4093. %--------------------------------------
  4094.  
  4095.  
  4096. %Repeater stuff
  4097. /repeater_special {beacon_special} def
  4098. /mark_repeater {} def
  4099. /repeater_font_size    { atom 15 mul } def
  4100. /repeater_symbol_size     {atom 10 mul}  def
  4101.  
  4102. /Print_repeater
  4103.     {
  4104.     /bad_loc false def
  4105.     /lat -90.0 def
  4106.     /lon -180.0 def
  4107.     repeater_color setrgbcolor
  4108.  
  4109. % If we have more than 2 digits in the grid locator, then proceed
  4110.     /loc_len repeater_fields 2 get length def
  4111.     loc_len 2 ge
  4112.         {
  4113.         repeater_fields 2 get
  4114.         grid_to_lat_lon
  4115.         }
  4116.         {
  4117.         /bad_loc false def
  4118.         } ifelse
  4119.  
  4120.     bad_loc not false
  4121.     repeaters_plotted
  4122.         {
  4123.         repeater_fields 0 get
  4124.         % have string which is freq with +/- at end
  4125.         % Can't convert to int in same way as for beacon (cvi)
  4126.         % threfore look for numbers before decimal point
  4127.         (.) search
  4128.             {
  4129.             %roll the MHz down the stack
  4130.             3 1 roll
  4131.             pop pop % pop the (.) and kHz+/- string
  4132.             cvi eq {not} if
  4133.             }
  4134.             {
  4135.             pop    % bad freq
  4136.             } ifelse
  4137.         } forall and
  4138.  
  4139.         {
  4140.         /beam_heading repeater_fields 4 get def
  4141.         beam_heading -1 eq
  4142.             {
  4143.             /beam_half_width 179.999 def
  4144.             /beam_heading 360 exch def
  4145.             }
  4146.             {
  4147.             /beam_half_width 35 def
  4148.             } ifelse
  4149.  
  4150.         correct_azimuth
  4151.  
  4152.         /pwr repeater_fields 3 get dup
  4153.         0.0 le { pop 0 }{ 2 mul log cvi } ifelse  def
  4154.  
  4155.     gsave
  4156.         3 atom mul setlinewidth
  4157.         %0 setgray
  4158.         lat lon lat_lon2xy translate
  4159.         gsave
  4160.         mark_repeater
  4161.     grestore
  4162.     gsave
  4163.  
  4164.         beam_half_width 35 ne { /repeater_symbol_size repeater_symbol_size 1.5 div def } if
  4165.         450 beam_heading sub rotate newpath
  4166.         0 0 repeater_symbol_size 0 360 arc
  4167.         gsave
  4168.         %1.0 setgray
  4169.         6 atom mul setlinewidth stroke
  4170.         grestore stroke
  4171.  
  4172.         beam_half_width 35 eq
  4173.             {
  4174.                 0 0 repeater_symbol_size 315 45 arc
  4175.                 0 0 repeater_symbol_size 3 div 65 295 arcn closepath ffill
  4176.             }{
  4177.                 0 0 repeater_symbol_size 360 beam_half_width sub beam_half_width arc
  4178.                 0 0 repeater_symbol_size 3 div beam_half_width 360 beam_half_width sub arcn closepath ffill
  4179.             } ifelse
  4180.  
  4181.         0 0 repeater_symbol_size 0 360 arc stroke
  4182.  
  4183.         pwr 0 gt
  4184.             {
  4185.             0 0 repeater_symbol_size 7 mul 3 div 360 beam_half_width sub beam_half_width arc
  4186.             0 0 repeater_symbol_size 5 mul 3 div beam_half_width 360 beam_half_width sub arcn
  4187.             closepath ffill
  4188.  
  4189.             pwr 1 gt
  4190.                 {
  4191.                 0 0 repeater_symbol_size 12 mul 3 div 360 beam_half_width sub beam_half_width arc
  4192.                 0 0 repeater_symbol_size 10 mul 3 div beam_half_width 360 beam_half_width sub arcn
  4193.                 closepath ffill
  4194.                 } if
  4195.             } if
  4196.         grestore
  4197.         repeater_font findfont repeater_font_size scalefont setfont
  4198.         %repeater_color setrgbcolor
  4199.         repeater_fields 5 get  0 eq
  4200.         {
  4201.             0 pwr 1 add 4 mul 1 add 3 div repeater_symbol_size mul moveto
  4202.         }
  4203.         {
  4204.             0 pwr 1 add 4 mul 1 add 3 div repeater_symbol_size mul
  4205.             repeater_font_size add neg moveto
  4206.         } ifelse
  4207.         currentpoint
  4208.         repeater_fields 0 get dup stringwidth pop 2 div neg 0 rmoveto halo
  4209.         moveto 0 repeater_font_size
  4210.         repeater_fields 5 get 0 ne { neg } if rmoveto
  4211.         repeater_fields 1 get dup stringwidth pop 2 div neg 0 rmoveto halo
  4212.         grestore
  4213.  
  4214.     }
  4215.     {
  4216.     } ifelse
  4217.  
  4218. } def
  4219.  
  4220.  
  4221. %--------------------------------------
  4222. /draw_worked_grid_square
  4223. {
  4224.     %grid square locator 4 char string (eg FM19) on stack
  4225.     grid_to_lat_lon
  4226.     % grid is a 2deg by 1deg rectangle
  4227.     % the lat/lon returned is the center of the square
  4228.     /lat lat 0.5 sub def
  4229.     /lon lon 1.0 sub def
  4230.     % the lat/lon returned is the bottom left corner
  4231.  
  4232.  
  4233.  
  4234.     % 1 atom mul setlinewidth
  4235.     worked_grid_square_color setrgbcolor
  4236.     newpath
  4237.  
  4238.     % sweep along edges of grids in increments of 1/10th
  4239.     % of edge length (to make grid edges curved).
  4240.  
  4241.     %adjust lat lon to bottom left corner of grid square
  4242.  
  4243.     lat    lon lat_lon2xy moveto
  4244.  
  4245.     0 1 10
  4246.         {
  4247.         /temp exch def
  4248.         lat    lon 2 temp mul 10 div add    lat_lon2xy lineto
  4249.         } for % sweep along bottom edge
  4250.  
  4251.     0 1 10
  4252.         {
  4253.         /temp exch def
  4254.         lat 1 temp mul 10 div add    lon 2 add    lat_lon2xy lineto
  4255.         } for % sweep up eastern edge
  4256.  
  4257.     10 -1 0
  4258.         {
  4259.         /temp exch def
  4260.         lat 1 add    lon 2 temp mul 10 div add lat_lon2xy lineto
  4261.         } for % sweep along top edge
  4262.  
  4263.     10 -1 0
  4264.         {
  4265.         /temp exch def
  4266.         lat 1 temp mul 10 div add    lon lat_lon2xy lineto
  4267.         } for % sweep down western edge
  4268.     closepath
  4269.     fill
  4270. }def %draw_worked_grid_square
  4271.  
  4272.  
  4273.  
  4274.  
  4275. %--------------------------------------
  4276. /take_a_sighting
  4277. {
  4278.         info_on_other_guy
  4279.         {
  4280.             draw_distance_bearing_lines
  4281.             {
  4282.                 newpath
  4283.                 2.5 atom mul setlinewidth
  4284.                 0 0 moveto
  4285.                 lat    lon lat_lon2xy lineto % rover's location
  4286.                 stroke
  4287.             } if %draw_distance_bearing_lines
  4288.  
  4289.             show_bearing
  4290.             {
  4291.                 %go to half way out
  4292.                 lat lon gc
  4293.                 %dist bearing on stack
  4294.                 dup /bearing exch def
  4295.                 %divide distance by half, and keep copy of dist
  4296.                 exch dup /dist exch def 2 div exch
  4297.                 distance_bearing2xy moveto    %go there
  4298.                 %convert compass origin and direction of rotation to cartesian system
  4299.                 bearing neg 90 add rotate
  4300.                 0 10 atom mul rmoveto
  4301.                 bearing cvi temp_string cvs dup stringwidth pop 2 div neg 0 rmoveto show
  4302.                 0 10 atom mul neg rmoveto
  4303.                 bearing 90 sub rotate
  4304.             }if %show_bearing
  4305.  
  4306.             show_distance
  4307.             {
  4308.                 dist 2 div bearing distance_bearing2xy moveto    %go there
  4309.                 bearing neg 90 add rotate
  4310.                 0 30 atom mul neg rmoveto
  4311.                 %convert deg to km, find string width, offset, show
  4312.                 dist deg2km cvi temp_string cvs dup stringwidth pop 2 div neg 0 rmoveto show
  4313.                 ( km) show
  4314.                 0 30 atom mul rmoveto
  4315.                 bearing 90 sub rotate
  4316.             } if %show_distance
  4317.         } if %info_on_other_guy
  4318. }def %take_a_sighting
  4319.  
  4320.  
  4321.  
  4322. %--------------------------------------
  4323. /draw_mountain_symbol
  4324. {
  4325.     % mountain symbol is a filled black triangle
  4326.     % position on paper is already defined at entry into this routine
  4327.     % the distance from the center of an isoceles triangle to the top
  4328.     % is cos(30)x 2/3 = 0.577 = tan(30)
  4329.     /mountain_symbol_size atom 10 mul def
  4330.     %/mountain_symbol_size atom 40 mul def
  4331.     newpath
  4332.     %black setrgbcolor
  4333.     lat    lon lat_lon2xy moveto    % mountain's location
  4334.     0 mountain_symbol_size 0.577 mul rmoveto    % to top of triangle
  4335.     mountain_symbol_size 0.5 mul neg mountain_symbol_size 0.866 mul neg rlineto    %bottom left
  4336.     mountain_symbol_size 0 rlineto    %bottom right
  4337.     mountain_symbol_size 0.5 mul neg mountain_symbol_size 0.866 mul rlineto    %top
  4338.     closepath %
  4339.     fill
  4340. } def
  4341. %--------------------------------------
  4342. /draw_mountain
  4343. % on stack - a string of the type Mt. Kearsarge:FN43bj:1500m:
  4344. %                                                         or  Mt. Kearsarge:FN43bj::
  4345. {
  4346.     %(mountain \n) print
  4347.     (:) search
  4348.     {
  4349.         /mountain_name exch def
  4350.         pop % (:)
  4351.         (:) search
  4352.         {
  4353.             grid_to_lat_lon
  4354.             bad_loc not
  4355.                 {
  4356.                     % valid location
  4357.                     draw_mountain_symbol
  4358.                     pop % (:)
  4359.                     (:) search    %look for elevation string
  4360.                     {
  4361.                         /elevation_string exch def
  4362.                         pop % (:)
  4363.                     } if % elevation_string found
  4364.                 }
  4365.                 {
  4366.                     pop    exit     %bad location
  4367.                 } ifelse % valid location
  4368.  
  4369.         % print strings
  4370.         % put mountain_name above mountain symbol
  4371.         % put elevation (if known) below mountain_symbol
  4372.         % rover strings will be put to the left and right of the
  4373.         % location, so if a rover is on the mountain, the strings
  4374.         % will not overlap.
  4375.  
  4376.     mountain_font findfont mountain_font_size scalefont setfont
  4377.         mountain_font_color setrgbcolor
  4378.  
  4379.  
  4380.  
  4381.         lat    lon lat_lon2xy moveto    % mountain's location
  4382.         mountain_name
  4383.     dup stringwidth pop 2 div neg
  4384.     atom 20 mul rmoveto
  4385.         show
  4386.  
  4387.         lat    lon lat_lon2xy moveto    % mountain's location
  4388.         elevation_string
  4389.     dup stringwidth pop 2 div neg
  4390.     atom 40 mul neg rmoveto
  4391.         show
  4392.  
  4393.         take_a_sighting
  4394.  
  4395.  
  4396.         } % if (:) infront of grid_locator
  4397.         {
  4398.         } ifelse % grid_locator
  4399.     } % search found a `:', hopefully a name
  4400.     {
  4401.         % no contenders for a mountain name, print error message
  4402.         (error: no mountain name \n) print
  4403.     } ifelse % search for :
  4404. }def
  4405.  
  4406. %--------------------------------------
  4407. % VW beetle
  4408. /beetle
  4409. {
  4410.     % alright, alright, so it's a dumb looking beetle...
  4411.     % so send me a better one.
  4412.  
  4413.     %uses lat lon (globals produced from grid_to_lat_lon)
  4414.     /rover_symbol_size atom 0.7 mul def
  4415.     rover_symbol_color setrgbcolor  % color in az_ini.ps
  4416.     5 rover_symbol_size mul setlinewidth
  4417.  
  4418.     %(lat lon) lat lon pstack pop pop pop
  4419.  
  4420.     lat    lon lat_lon2xy % rover location on stack
  4421.     /rover_y exch def
  4422.     /rover_x exch def
  4423.  
  4424.  
  4425.     newpath
  4426.     % draw front wheel
  4427.     rover_x -20 rover_symbol_size mul add rover_y 10 rover_symbol_size mul 0 360 arc
  4428.     closepath
  4429.     stroke
  4430.  
  4431.     % draw back wheel
  4432.     newpath
  4433.     rover_x 20 rover_symbol_size mul add rover_y 10 rover_symbol_size mul 0 360 arc
  4434.     closepath
  4435.     stroke
  4436.  
  4437.     %hood
  4438.     newpath
  4439.     rover_x -20 rover_symbol_size mul add rover_y 25 rover_symbol_size mul 75 180 arc
  4440.   stroke
  4441.  
  4442.     %back end of body
  4443.     newpath
  4444.     rover_x 10 rover_symbol_size mul add rover_y 40 rover_symbol_size mul 0 90 arc
  4445.     -5 rover_symbol_size mul 0 rlineto
  4446.     0 30 rover_symbol_size mul rlineto
  4447.     0 -30 rover_symbol_size mul rlineto
  4448.     -10 rover_symbol_size mul 0 rlineto
  4449.     -10 rover_symbol_size mul -10 rover_symbol_size mul rlineto
  4450.     stroke
  4451. }def
  4452.  
  4453. %--------------------------------------
  4454. /draw_rover_symbol
  4455. {
  4456.     beetle    %VW beetle
  4457.     %bronco     %someone want to make up a white Ford Bronco?
  4458. } def
  4459. %--------------------------------------
  4460. /draw_rover
  4461. % on stack - a string of the type Mt. Kearsarge:FN43bj:1500m:
  4462. %                                                         or  Mt. Kearsarge:FN43bj::
  4463. {
  4464.     %(rover \n) print
  4465.     %pstack
  4466.     (:) search
  4467.     {
  4468.         /rover_name exch def
  4469.         pop % (:)
  4470.         (:) search
  4471.         {
  4472.             grid_to_lat_lon
  4473.             bad_loc not
  4474.                 {
  4475.                     % valid location
  4476.                     draw_rover_symbol
  4477.                     pop % (:)
  4478.                     (:) search    %look for elevation string
  4479.                     {
  4480.                         /rover_comment exch def
  4481.                         pop % (:)
  4482.                     } if % rover_comment found
  4483.                 }
  4484.                 {
  4485.                     pop    exit     %bad location
  4486.                 } ifelse % valid location
  4487.  
  4488.         % print strings
  4489.         % put over_name at left or rover symbol
  4490.         % put comment (or whatever) to right of rover_symbol
  4491.         % mountain strings will be put to the above and below the
  4492.         % location, so if a rover is on the mountain, the strings
  4493.         % will not overlap.
  4494.  
  4495.     rover_font findfont rover_font_size scalefont setfont
  4496.         rover_font_color setrgbcolor
  4497.  
  4498.         lat    lon lat_lon2xy moveto    % rover's location
  4499.         rover_name
  4500.     dup stringwidth    pop neg 40 atom mul sub % fix x
  4501.         rover_font_size 4 div neg % fix y
  4502.     rmoveto
  4503.         show
  4504.  
  4505.         lat    lon lat_lon2xy moveto    % rover's location
  4506.         rover_comment
  4507.         50 atom mul    %fix x
  4508.         rover_font_size 4 div neg % fix y
  4509.         rmoveto
  4510.         show
  4511.  
  4512.         take_a_sighting
  4513.  
  4514.         } % if (:) infront of grid_locator
  4515.         {
  4516.         } ifelse % grid_locator
  4517.     } % search found a `:', hopefully a name
  4518.     {
  4519.         % no contenders for a rover name, print error message
  4520.         (error: no rover name \n) print
  4521.     } ifelse % search for :
  4522. }def
  4523.  
  4524.  
  4525. %--------------------------------------
  4526.  
  4527. /halo
  4528. {
  4529.     % This erases the screen around the annotation, so that it is readable
  4530.     % We write the character outlines with a very thick white pen first.
  4531.     gsave
  4532.     currentpoint 1.0 setgray  5 atom mul setlinewidth
  4533.     2 index true charpath stroke moveto
  4534.     grestore show
  4535. } def
  4536.  
  4537. %--------------------------------------
  4538.  
  4539. /ffill
  4540. {
  4541.     gsave 1.0 setgray 5 atom mul setlinewidth stroke grestore fill
  4542. } def
  4543.  
  4544. %--------------------------------------
  4545. /parse_nmea_data
  4546. %line on stack like
  4547. % - geographic lat lon
  4548. %(GLL,4130.34,N,7135.42,W)
  4549. % or - bearing origin to dest
  4550. %(BOD,120,T, 125,M,####,####)
  4551. % or - bearing to waypoint along great circle
  4552. %(BWC,235959,4359.00,N,7059.00,W,180,T,185,M,252.5,N,####)
  4553. {
  4554.     (,) search
  4555.     {
  4556.         %has commas, probably a valid nmea data line
  4557.         { % loop through all GPS==$GP data types
  4558.  
  4559.             dup (GLL) eq
  4560.             {
  4561.                 % is there a (GLL) before the `,'
  4562.                 % then the line is a Geographic Lat Lot
  4563.                 % (GLL) is on top of stack
  4564.                 % (,) is next
  4565.                 % (the rest of the GLL string) is next
  4566.                 %
  4567.                 %(found GLL \n) print_notice
  4568.                 pop pop
  4569.                 extract_GLL
  4570.                 %pop
  4571.                 exit
  4572.             } if % annotate
  4573.  
  4574.             dup (BOD) eq
  4575.             {
  4576.                 % is there a (BOD) before the `,'
  4577.                 % then the line is a Geographic Lat Lot
  4578.                 % (BOD) is on top of stack
  4579.                 % (,) is next
  4580.                 % (the rest of the BOD string) is next
  4581.                 %
  4582.                 % (found BOD \n) print_notice
  4583.                 pop pop
  4584.                 extract_BOD
  4585.                 %pop
  4586.                 exit
  4587.             } if % annotate
  4588.  
  4589.             dup (BWC) eq
  4590.             {
  4591.                 % is there a (BWC) before the `,'
  4592.                 % then the line is a Geographic Lat Lot
  4593.                 % (BWC) is on top of stack
  4594.                 % (,) is next
  4595.                 % (the rest of the BWC string) is next
  4596.                 %
  4597.                 % (found BWC \n) print_notice
  4598.                 pop pop
  4599.                 extract_BWC
  4600.                 %pop
  4601.                 exit
  4602.             } if % annotate
  4603.  
  4604.             % unknown $GP data type
  4605.             (unknown $GP data type ignored: )print_notice = pop pop exit
  4606.  
  4607.  
  4608.         } loop % look for nmea data types (GLL, BWC, BOD)
  4609.     }% if of ifelse of found (,)
  4610.     {
  4611.         (bad nmea line \n)print_notice
  4612.         pop % whole line
  4613.         exit %bad nmea line
  4614.     }ifelse
  4615. }def
  4616.  
  4617.  
  4618.  
  4619. %--------------------------------------
  4620. /parse_data_type
  4621. %line on stack like (repeater)(:)(147.105+   NV3Z      FM18rx    100    270)
  4622. {
  4623.     {
  4624.         dup (grid) eq %grid squares
  4625.         {
  4626.             pop pop
  4627.             (:) search
  4628.             {
  4629.                 cvi /band exch def
  4630.                 pop % the `:'
  4631.                 grid_bands_plotted
  4632.                 {
  4633.                     band eq
  4634.                     {
  4635.                         draw_worked_grid_square
  4636.                     } if % this band
  4637.                 } forall % bands
  4638.             } if % search found a `:'
  4639.             exit
  4640.         } if % grid
  4641.  
  4642.         %If we get here, we have found a .dat file which is not
  4643.         %a worked grid dat file (grid.dat). This is one of the
  4644.         %places where we can draw grid square labels and borders.
  4645.         %Did we choose to do so?
  4646.  
  4647.         grid_square_labels_on_paper
  4648.         not
  4649.         draw_grid_square_borders_and_labels_before_regular_dat_files
  4650.         and
  4651.         {
  4652.             draw_compass_distance_lines_grid_square_labels_borders_outer_border
  4653.             /grid_square_labels_on_paper true def
  4654.         }if % we haven't already drawn the labels
  4655.                 % and we want to do it before drawing .dat file data
  4656.  
  4657.         dup (annotate) eq
  4658.         {
  4659.             % is there a `annotate' before the `:'
  4660.             % then the line is an annotation
  4661.             % (annotate) is on top of stack
  4662.             % (:) is next
  4663.             % (the whole annotation string) is next
  4664.             pop pop
  4665.             extract_annotation
  4666.             exit
  4667.         } if % annotate
  4668.  
  4669.         dup (beacon) eq
  4670.         {
  4671.             pop pop
  4672.             /beacon on def
  4673.             /beacon_color {beacon_font_color} def
  4674.             /mark_beacon {} def
  4675.             extract_beacon
  4676.             /beacon off def
  4677.             exit
  4678.         } if % beacon
  4679.  
  4680.         dup (BEACON) eq
  4681.         {
  4682.             pop pop
  4683.             /beacon_color {beacon_special_color} def
  4684.             /mark_beacon {beacon_special} def
  4685.             extract_beacon
  4686.             exit
  4687.         } if % BEACON
  4688.  
  4689.         dup (dxcc) eq
  4690.         {
  4691.             % dxcc country
  4692.             pop pop
  4693.             %(got here (d) \n) print
  4694.             %pstack
  4695.             /dxcc_line exch def    %going to hack this line, need to be able to recover original later
  4696.             /big_D false def
  4697.             dxcc_special_country
  4698.             extract_band_mode
  4699.             exit
  4700.         } if % dxcc
  4701.  
  4702.         dup (DXCC) eq
  4703.         {
  4704.             % dxcc special country
  4705.             pop pop
  4706.             /dxcc_line exch def    %going to hack this line, need to be able to recover original later
  4707.             /big_D true def
  4708.             dxcc_special_country_2
  4709.             extract_band_mode
  4710.             exit
  4711.         } if % DXCC
  4712.  
  4713.  
  4714.         dup (mountain) eq %
  4715.         {
  4716.             pop pop
  4717.             % on stack - a string of the type "Mt. Kearsarge:FN43bj:1500m:"
  4718.             /info_on_other_guy off def % must be defined
  4719.             mountain_symbol_color setrgbcolor  % color in az_ini.ps
  4720.             draw_mountain
  4721.             exit
  4722.         } if % mountain
  4723.  
  4724.         dup (MOUNTAIN) eq %
  4725.         {
  4726.             pop pop
  4727.             /info_on_other_guy on def
  4728.             % on stack - a string of the type "Mt. Kearsarge:FN43bj:1500m:"
  4729.             mountain_symbol_special_color setrgbcolor  % color in az_ini.ps
  4730.             draw_mountain
  4731.             /info_on_other_guy off def
  4732.             exit
  4733.         } if % mountain
  4734.  
  4735.         dup (repeater) eq
  4736.         {
  4737.             pop pop
  4738.             /repeater_color {repeater_font_color} def
  4739.             /mark_repeater {} def
  4740.             extract_repeater
  4741.             exit
  4742.         } if %repeater
  4743.  
  4744.         dup (REPEATER) eq
  4745.         {
  4746.             pop pop
  4747.             /repeater_color {repeater_special_color} def
  4748.             /mark_repeater {repeater_special} def
  4749.             extract_repeater
  4750.             exit
  4751.         } if %REPEATER
  4752.  
  4753.         dup (rover) eq % reading a rover line
  4754.         {
  4755.             pop pop
  4756.             % on stack - a string of the type "Mt. Kearsarge:FN43bj:1500m:"
  4757.             /info_on_other_guy off def % must be defined
  4758.             draw_rover
  4759.             exit
  4760.         } if % rover
  4761.  
  4762.         dup (ROVER) eq % reading a ROVER line
  4763.         {
  4764.             pop pop
  4765.             % on stack - a string of the type "Mt. Kearsarge:FN43bj:1500m:"
  4766.             /info_on_other_guy on def % must be defined
  4767.             draw_rover
  4768.             /info_on_other_guy off def % must be defined
  4769.             exit
  4770.         } if % ROVER
  4771.  
  4772.         % If loop falls through to here, then this line is an unknown data type
  4773.         (Error: unknown data type -) print pstack pop pop pop exit
  4774.  
  4775.     } loop % look for data types (repeaters, beacons etc)
  4776. }def
  4777.  
  4778. %--------------------------------------
  4779. % Get each line until EOF
  4780. %
  4781. %/linebuf 1024 string def
  4782. /linebuf 256 string def            % 256 makes debugging dumps easier to handle - Joe
  4783.  
  4784. /line_cnt 0 def
  4785.  
  4786. /get_line
  4787. {
  4788.     {
  4789.         % loop until we run out of file names
  4790.         next_file not
  4791.         {
  4792.             Termination
  4793.             exit
  4794.         } if %not next_file
  4795.  
  4796.         /BigBang save def    % Snapshot of memory state saved at each file
  4797.                     % saved state is stored as BigBang
  4798.                     % When we restore VM goes back to its
  4799.                     % condition at 'BigBang'
  4800.  
  4801.         {
  4802.             data_file linebuf readline
  4803.             {
  4804.                 %dup    % two copies of line, one for testing, one for reading
  4805.                 {
  4806.                     (%) anchorsearch % looking for (%) at start of line - ie comment
  4807.                     {
  4808.                         pop % (%)
  4809.                         %found comment line - ignore
  4810.                         %pstack (comment \n) print
  4811.                         pop % rest of comment
  4812.                         %pop % original copy of comment
  4813.                         %pstack (comment \n) print
  4814.                         exit
  4815.                     }if % (%) found at start of line
  4816.  
  4817.                     ($GP) anchorsearch % looking for ($GP) at start of line - ie GPS NMEA data
  4818.                     {
  4819.                         pop % $GP string
  4820.                         %found NMEA data
  4821.                         %pstack (NMEA line \n) print
  4822.                         parse_nmea_data
  4823.                         %pop %original copy of string that was duplicated
  4824.                         exit
  4825.                     }    if % ($) found at start of line
  4826.  
  4827.                     %default of case like statement
  4828.                     %{
  4829.                         %pop % remove dup'ed copy of line
  4830.                         %(non comment \n) print
  4831.                         % line does not start with (%)
  4832.                         % does it have a (:) in the line?
  4833.                         % if the input line contains a ':' we treat the line as special text -
  4834.                         % eg annotation, beacon, dxcc, ...
  4835.                         % if no (:) we treat the line as a path line.
  4836.                         % Thus we can concatonate the path (wdb) and the test files
  4837.                         % and pass them as one stream of standard input
  4838.  
  4839.                         (:) search
  4840.                         {
  4841.                             % there is a (:) in the line
  4842.                             parse_data_type
  4843.                         } % search finds (:)
  4844.                         {
  4845.                             %we've found a map line,
  4846.                             %if we haven't printed the grid square borders etc
  4847.                             %then check if we're supposed to.
  4848.  
  4849.                             grid_square_labels_on_paper
  4850.                             not
  4851.                             draw_grid_square_borders_and_labels_before_maps
  4852.                             and
  4853.                                 {
  4854.                                 %(grid_square_labels_on_paper) pstack pop
  4855.                                 draw_compass_distance_lines_grid_square_labels_borders_outer_border
  4856.                                 /grid_square_labels_on_paper true def
  4857.                                 %if we just change /grid_square_labels_on_paper here it will
  4858.                                 %be blown away by the restore below, so push it on the stack
  4859.                                 %before restoring (see restore below)
  4860.                                 }if % we haven't already drawn the labels
  4861.                                         % and we want to do it before drawing .wdb file data
  4862.  
  4863.                             extract_coord
  4864.                         } ifelse % no (:) presumably is wdb file
  4865.                     exit
  4866.                     %} ifelse % no (%) at start of line - normal data line
  4867. %    %                line_cnt 500 ge
  4868. %    %                {
  4869.                         % We recover memory after 500 paths (not input lines)
  4870.                         % We don't realise that we have exceeded our quota of
  4871.                         % paths until the beginning of the next path, so we
  4872.                         % need to save that first point of the (next) path from
  4873.                         % being destroyed
  4874.  
  4875. %    %                    0 ini 0 lat 0 lon
  4876.  
  4877. %    %                    %push the name /grid_square_labels_on_paper on the stack
  4878. %    %                    /grid_square_labels_on_paper
  4879. %    %                    %then its value
  4880. %    %                    grid_square_labels_on_paper
  4881. %    %                    %then restore (which doesn't change the stack)
  4882. %    %                    BigBang restore
  4883. %    %                    %then pop the value off the stack
  4884. %    %                    def
  4885. %    %                    /BigBang save def
  4886. %    %                    [ 4 1 roll ] coord 0 3 -1 roll put /i 1 def
  4887. %    %                    /line_cnt 0 def
  4888. %    %                } if %line_cnt > 500
  4889.                 }loop
  4890.             }% if of ifelse of input line
  4891.             {
  4892.                 clear exit
  4893.             } ifelse %no input line
  4894.         } loop % readline
  4895.         coord 0 get null ne
  4896.         {
  4897.             crunch_path
  4898.         } if
  4899.  
  4900.  
  4901.  
  4902.         %To recover variables from inside the save/restore loop
  4903.         %you have to push the value and name on the stack
  4904.         %then restore (which doesn't affect the stack)
  4905.         %then def after the restore
  4906.  
  4907.         %Check
  4908.         %(Before restore \n) print_notice
  4909.         %waypoint_distance = (waypoint_distance \n) print_notice
  4910.         %waypoint_bearing = (waypoint_bearing \n) print_notice
  4911.         %hour = (BWC_hour \n) print_notice
  4912.         %min = (BWC_min \n) print_notice
  4913.         %lat_QTH = (lat_QTH \n) print_notice
  4914.         %lon_QTH = (lon_QTH \n) print_notice
  4915.         %grid_square_labels_on_paper    = (grid_square_labels_on_paper \n) print_notice
  4916.  
  4917.         /grid_square_labels_on_paper    %push the variable name on the stack
  4918.         grid_square_labels_on_paper        %then its value
  4919.         /lat_QTH lat_QTH                            %similarly
  4920.         /lon_QTH lon_QTH
  4921.         /hour         hour
  4922.         /min         min
  4923.  
  4924.         BigBang restore                                %then restore (which doesn't change the stack)
  4925.         def def def def def
  4926.         %def def
  4927.  
  4928.         %Check
  4929.         %(After restore \n) print_notice
  4930.         %hour = (hour \n) print_notice
  4931.         %min = (min \n) print_notice
  4932.         %lat_QTH = (lat_QTH \n) print_notice
  4933.         %lon_QTH = (lon_QTH \n) print_notice
  4934.         %grid_square_labels_on_paper    = (grid_square_labels_on_paper \n) print_notice
  4935.  
  4936.     } loop % get_line
  4937. } def % get_line
  4938.  
  4939. %--------------------------------------
  4940. /draw_compass_distance_lines_grid_square_labels_borders_outer_border
  4941.  
  4942. {
  4943. mark
  4944.  
  4945. %lat_QTH = (lat_QTH draw_compass... \n) print_notice
  4946. %lon_QTH = (lon_QTH draw_compass... \n) print_notice
  4947.  
  4948.  
  4949. /ground_state save def
  4950.         % We can reclaim a lot of VMemory after the preliminaries are over
  4951.         % A lot of memory is used up in the Letter/Number grid routines
  4952.  
  4953.  
  4954. draw_greyline
  4955.     {
  4956.     calculate_sun_position
  4957.     az_dict /sun_lat known
  4958.     az_dict /sun_lon known
  4959.     and
  4960.         {
  4961.         draw_sun_symbol
  4962.         greyline
  4963.         }
  4964.         {
  4965.             % date/time/sun_lat/sun_lon not entered in az_ini.ps
  4966.             % or no NMEA.DAT file
  4967.             (Greyline: sun_lat and/or sun_lon info can't be calculated \n) print_notice
  4968.         }ifelse % sun_lat, sun_lon not found
  4969.     } if
  4970.  
  4971. draw_number_square_borders map_scale_deg 50 lt and
  4972.     {
  4973.         % 0.2 x 0.1 deg lat, lon lines
  4974.         grid_locator_fine
  4975.     } if
  4976.  
  4977. draw_number_square_labels map_scale_deg 50 lt and
  4978.     {
  4979.         % labels for 0.2 x 0.1 lines
  4980.         grid_locator_numbers_show
  4981.     } if
  4982.  
  4983. draw_letter_square_borders
  4984.     {
  4985.         % 2 x 1 deg lat, lon lines
  4986.         grid_locator_coarse
  4987.     } if
  4988.  
  4989. draw_letter_square_labels
  4990.     {
  4991.         % labels for 2 x 1 deg lines
  4992.         grid_locator_letters_show
  4993.     } if
  4994.  
  4995. distance_circles
  4996.     {
  4997.         distances_plotted
  4998.         {
  4999.             draw_distance_circles
  5000.         } forall % circle distances
  5001.         % rad is calculated in draw_distance_circles
  5002.         % unless of course you've left the array distances_plotted empty
  5003.         % and you aren't plotting anything at all
  5004.  
  5005.         az_dict /rad known
  5006.         {
  5007.             rad compass_rose
  5008.             draw_spokes
  5009.             rad label_compass_directions
  5010.             /draw_compass_circumference    off def
  5011.             /draw_compass_spokes        off def
  5012.         } if
  5013.     } if
  5014.  
  5015. % Must draw spokes before circumference as circumference routine
  5016. % labels the directions and these numbers will be covered by the spokes.
  5017.  
  5018.  
  5019. %just incase drawing spokes to antipodes with no compass circumference
  5020. draw_compass_spokes compass_spokes_to_antipodes and
  5021.     {
  5022.         draw_spokes
  5023.         /draw_compass_spokes off def
  5024.     } if
  5025.  
  5026. draw_compass_circumference {draw_bearing_rose} if
  5027.  
  5028. %draw_compass_spokes {draw_spokes} if
  5029.  
  5030. %draw_compass_circumference
  5031. %    {
  5032. %        (draw_compass_circumference \n) print_notice
  5033. %        rad label_compass_directions
  5034. %    } if
  5035.  
  5036. %draw_compass_circumference {rad label_compass_directions } if
  5037.  
  5038. % circular border representing the antipodes
  5039. %draw edge of the world whether it is off scale or not
  5040. draw_outer_border {    outer_border } if
  5041.  
  5042. ground_state restore    % return memory to the earlier state
  5043. cleartomark
  5044. } def
  5045.  
  5046. %--------------------------------------
  5047.  
  5048. /Termination
  5049. {
  5050.     %label_scale    %doesn't work here as is offset
  5051.  
  5052.     grid_square_labels_on_paper
  5053.     not
  5054.     {
  5055.         draw_compass_distance_lines_grid_square_labels_borders_outer_border
  5056.     }if % we haven't already drawn the labels
  5057.     /grid_square_labels_on_paper false def %just in case we add a routine after termination
  5058.  
  5059.  
  5060.     pstack        % This is a 'heads up', since there should not be
  5061.                         % any garbage on the stack.
  5062.     (elapsed time = ) print_notice
  5063.     usertime starttime sub 1000 div 10 string cvs print_notice
  5064.     ( seconds ) =
  5065.     (Cleaning up (will take a while if generating printer file).\n) print_notice
  5066.     showpage
  5067.         % do whatever we do at EOF
  5068. } def
  5069.  
  5070. %--------------------------------------
  5071.  
  5072. /label_scale
  5073. {
  5074.  
  5075.     newpath
  5076.  
  5077.     az_dict /Title known
  5078.         {
  5079.         /Helvetica findfont footer_label_height 2 mul scalefont setfont
  5080.         0 half_height footer_label_height 3 mul sub moveto
  5081.         Title
  5082.         stringwidth pop 2 div neg 0 rmoveto
  5083.         Title show
  5084.         } if
  5085.  
  5086.  
  5087.     /Helvetica findfont footer_label_height scalefont setfont
  5088.     half_width neg    half_height footer_label_height 6 mul sub neg moveto
  5089.     currentpoint (Azimuthal Equidistant Projection) show
  5090.  
  5091.     footer_label_height sub moveto currentpoint (From ) show QTH_name show
  5092.  
  5093.     footer_label_height 2 mul sub moveto currentpoint (Radial scale: ) show
  5094.     map_scale_deg short_side_in_cm div 90 div 10000 mul
  5095.     0.5 add                % for roundoff error
  5096.     cvi 10 string cvs show
  5097.     (km:1cm) show
  5098.  
  5099.     /Helvetica findfont footer_label_height 0.6 mul scalefont setfont
  5100.     footer_label_height 2 mul sub moveto
  5101.     ((C) Joseph Mack NA3T, Michael Katzmann NV3Z, 1994, 1995) show
  5102.  
  5103. }def
  5104.  
  5105. %--------------------------------------
  5106.  
  5107. /setup_dimensions
  5108. {
  5109.  
  5110. % find bounding box (fit to printable area)
  5111.  
  5112.     clippath pathbbox printer_fiddle
  5113.     3 -1 roll dup /yborder exch def    sub 2 div /ysize exch def
  5114.     exch dup /xborder exch def sub 2 div /xsize exch def
  5115.  
  5116.     xsize xborder add ysize yborder add translate
  5117.         % 0 0 is now in the centre
  5118.     xsize ysize lt { xsize }{ ysize } ifelse
  5119.  
  5120.     dup 72 div 2.54 mul /short_side_in_cm exch def
  5121.         % cm for map_scale
  5122.         % scale map so it is map_scale degrees accross + a bit for a border
  5123.         % short side is on stack
  5124.  
  5125.     az_dict /kms_per_cm known
  5126.     {
  5127.         kms_per_cm short_side_in_cm mul
  5128.         90 mul 10000 div        % thanks to Napoleon
  5129.         /map_scale_deg exch def
  5130.     } if
  5131.  
  5132.     map_scale_deg div
  5133.     dup scale                % from centre to edge
  5134.  
  5135.     /order_of_mag  map_scale_deg deg2km log cvi 10 exch exp def
  5136.  
  5137.                 % create a variable that's independent of scale
  5138.     clippath pathbbox    % This gives the bounding box to
  5139.     /half_height exch def    % the printable area
  5140.     /half_width  exch def
  5141.     pop pop
  5142.     /atom half_height 1000 div def    % this is a fraction of the screen
  5143.                 % we use as a size variable
  5144. } def
  5145.  
  5146. %--------------------------------------
  5147. % The body of the program
  5148. %
  5149.  
  5150. (\n\naz_proj.ps v1.0)print_notice
  5151. (\nCopyright(C) 1994, 1995 Michael Katzmann NV3Z & Joseph Mack NA3T)print_notice
  5152. (\nThis program comes with ABSOLUTELY NO WARRANTY\n\n)print_notice
  5153.  
  5154. use_automatic_option
  5155.     {process_options}        %automatic
  5156.     {process_options_manual}    %manual
  5157.     ifelse
  5158.  
  5159.  
  5160. center_offset not
  5161. {
  5162.     /lon_center lon_QTH def
  5163.     /lat_center lat_QTH def
  5164. } if
  5165.  
  5166.  
  5167. landscape % landscape requested?
  5168. {
  5169.     (Orientation: landscape\n) print_notice
  5170.     90 rotate
  5171. }{
  5172.     (Orientation: portrait\n) print_notice
  5173. }ifelse
  5174.  
  5175. setup_specific
  5176. setup_dimensions
  5177.  
  5178. % Print Legend before do center offset or else it will
  5179. % print in wrong spot (maybe off screen)
  5180.  
  5181. label_scale
  5182.  
  5183. % move centre to centre of interest
  5184. center_offset
  5185. {
  5186.     lat_center lon_center gc 180 add distance_bearing2xy translate
  5187. } if
  5188.  
  5189. 1.0 setmiterlimit    % looks better for rugged coastlines
  5190.  
  5191. % Read Data (from file or stdin)
  5192. % When sending to a real postscript printer
  5193. % (not a program in a computer which outputs the printer's native code)
  5194. % OR where there is no ARGUMENT given in ghostscript,
  5195. % the script (ie data eg .wdb file(s), dxcc, annotations & beacons  )
  5196. % must follow the instruction 'get_line'.
  5197. % i.e. the data must be concatenated onto this file (with say an editor).
  5198. % Otherwise give the names of data files as arguements to ghostscript
  5199. % or your postscript interpreter and let it handle the whole thing.
  5200.  
  5201. % Important: Whatever you feed the Postscipt printer, it must end with an EOF
  5202. % (always a ^D). Otherwise the printer will wait until it times out.
  5203. % You can concatenate the file contrld.ps onto the end of the data files
  5204. % if you have no other way of doing this or the spooler doesn't do it for you.
  5205. %
  5206. get_line
  5207. %--------------------------------------
  5208. %--------------------------------------az_proj.ps
  5209.